|
2 | 2 | using Microsoft.CodeAnalysis.CSharp; |
3 | 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; |
4 | 4 | using Semmle.Extraction.CSharp.Entities.Expressions; |
5 | | -using Semmle.Extraction.CSharp.Populators; |
6 | | -using Semmle.Extraction.Entities; |
7 | 5 | using Semmle.Extraction.Kinds; |
8 | 6 | using System; |
9 | 7 | using System.IO; |
10 | 8 | using System.Linq; |
11 | 9 |
|
12 | 10 | namespace Semmle.Extraction.CSharp.Entities |
13 | 11 | { |
14 | | - public interface IExpressionParentEntity : IEntity |
15 | | - { |
16 | | - /// <summary> |
17 | | - /// Whether this entity is the parent of a top-level expression. |
18 | | - /// </summary> |
19 | | - bool IsTopLevelParent { get; } |
20 | | - } |
21 | | - |
22 | 12 | internal class Expression : FreshEntity, IExpressionParentEntity |
23 | 13 | { |
24 | 14 | private readonly IExpressionInfo info; |
@@ -308,314 +298,4 @@ private void PopulateArgument(TextWriter trapFile, ArgumentSyntax arg, int child |
308 | 298 |
|
309 | 299 | public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; |
310 | 300 | } |
311 | | - |
312 | | - internal static class CallTypeExtensions |
313 | | - { |
314 | | - /// <summary> |
315 | | - /// Adjust the expression kind <paramref name="k"/> to match this call type. |
316 | | - /// </summary> |
317 | | - public static ExprKind AdjustKind(this Expression.CallType ct, ExprKind k) |
318 | | - { |
319 | | - if (k == ExprKind.ADDRESS_OF) |
320 | | - { |
321 | | - return k; |
322 | | - } |
323 | | - |
324 | | - switch (ct) |
325 | | - { |
326 | | - case Expression.CallType.Dynamic: |
327 | | - case Expression.CallType.UserOperator: |
328 | | - return ExprKind.OPERATOR_INVOCATION; |
329 | | - default: |
330 | | - return k; |
331 | | - } |
332 | | - } |
333 | | - } |
334 | | - |
335 | | - internal abstract class Expression<TExpressionSyntax> : Expression |
336 | | - where TExpressionSyntax : ExpressionSyntax |
337 | | - { |
338 | | - public TExpressionSyntax Syntax { get; } |
339 | | - |
340 | | - protected Expression(ExpressionNodeInfo info) |
341 | | - : base(info) |
342 | | - { |
343 | | - Syntax = (TExpressionSyntax)info.Node; |
344 | | - } |
345 | | - |
346 | | - /// <summary> |
347 | | - /// Populates expression-type specific relations in the trap file. The general relations |
348 | | - /// <code>expressions</code> and <code>expr_location</code> are populated by the constructor |
349 | | - /// (should not fail), so even if expression-type specific population fails (e.g., in |
350 | | - /// standalone extraction), the expression created via |
351 | | - /// <see cref="Expression.Create(Context, ExpressionSyntax, IEntity, int, ITypeSymbol)"/> will |
352 | | - /// still be valid. |
353 | | - /// </summary> |
354 | | - protected abstract void PopulateExpression(TextWriter trapFile); |
355 | | - |
356 | | - protected new Expression TryPopulate() |
357 | | - { |
358 | | - cx.Try(Syntax, null, () => PopulateExpression(cx.TrapWriter.Writer)); |
359 | | - return this; |
360 | | - } |
361 | | - } |
362 | | - |
363 | | - /// <summary> |
364 | | - /// Holds all information required to create an Expression entity. |
365 | | - /// </summary> |
366 | | - internal interface IExpressionInfo |
367 | | - { |
368 | | - Context Context { get; } |
369 | | - |
370 | | - /// <summary> |
371 | | - /// The type of the expression. |
372 | | - /// </summary> |
373 | | - AnnotatedTypeSymbol? Type { get; } |
374 | | - |
375 | | - /// <summary> |
376 | | - /// The location of the expression. |
377 | | - /// </summary> |
378 | | - Extraction.Entities.Location Location { get; } |
379 | | - |
380 | | - /// <summary> |
381 | | - /// The kind of the expression. |
382 | | - /// </summary> |
383 | | - ExprKind Kind { get; } |
384 | | - |
385 | | - /// <summary> |
386 | | - /// The parent of the expression. |
387 | | - /// </summary> |
388 | | - IExpressionParentEntity Parent { get; } |
389 | | - |
390 | | - /// <summary> |
391 | | - /// The child index of the expression. |
392 | | - /// </summary> |
393 | | - int Child { get; } |
394 | | - |
395 | | - /// <summary> |
396 | | - /// Holds if this is an implicit expression. |
397 | | - /// </summary> |
398 | | - bool IsCompilerGenerated { get; } |
399 | | - |
400 | | - /// <summary> |
401 | | - /// Gets a string representation of the value. |
402 | | - /// null is encoded as the string "null". |
403 | | - /// If the expression does not have a value, then this |
404 | | - /// is null. |
405 | | - /// </summary> |
406 | | - string ExprValue { get; } |
407 | | - |
408 | | - NullableFlowState FlowState { get; } |
409 | | - } |
410 | | - |
411 | | - /// <summary> |
412 | | - /// Explicitly constructed expression information. |
413 | | - /// </summary> |
414 | | - internal class ExpressionInfo : IExpressionInfo |
415 | | - { |
416 | | - public Context Context { get; } |
417 | | - public AnnotatedTypeSymbol? Type { get; } |
418 | | - public Extraction.Entities.Location Location { get; } |
419 | | - public ExprKind Kind { get; } |
420 | | - public IExpressionParentEntity Parent { get; } |
421 | | - public int Child { get; } |
422 | | - public bool IsCompilerGenerated { get; } |
423 | | - public string ExprValue { get; } |
424 | | - |
425 | | - public ExpressionInfo(Context cx, AnnotatedTypeSymbol? type, Extraction.Entities.Location location, ExprKind kind, |
426 | | - IExpressionParentEntity parent, int child, bool isCompilerGenerated, string value) |
427 | | - { |
428 | | - Context = cx; |
429 | | - Type = type; |
430 | | - Location = location; |
431 | | - Kind = kind; |
432 | | - Parent = parent; |
433 | | - Child = child; |
434 | | - ExprValue = value; |
435 | | - IsCompilerGenerated = isCompilerGenerated; |
436 | | - } |
437 | | - |
438 | | - // Synthetic expressions don't have a flow state. |
439 | | - public NullableFlowState FlowState => NullableFlowState.None; |
440 | | - } |
441 | | - |
442 | | - /// <summary> |
443 | | - /// Expression information constructed from a syntax node. |
444 | | - /// </summary> |
445 | | - internal class ExpressionNodeInfo : IExpressionInfo |
446 | | - { |
447 | | - public ExpressionNodeInfo(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child) : |
448 | | - this(cx, node, parent, child, cx.GetTypeInfo(node)) |
449 | | - { |
450 | | - } |
451 | | - |
452 | | - public ExpressionNodeInfo(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child, TypeInfo typeInfo) |
453 | | - { |
454 | | - Context = cx; |
455 | | - Node = node; |
456 | | - Parent = parent; |
457 | | - Child = child; |
458 | | - TypeInfo = typeInfo; |
459 | | - Conversion = cx.GetModel(node).GetConversion(node); |
460 | | - } |
461 | | - |
462 | | - public Context Context { get; } |
463 | | - public ExpressionSyntax Node { get; private set; } |
464 | | - public IExpressionParentEntity Parent { get; set; } |
465 | | - public int Child { get; set; } |
466 | | - public TypeInfo TypeInfo { get; } |
467 | | - public Microsoft.CodeAnalysis.CSharp.Conversion Conversion { get; } |
468 | | - |
469 | | - public AnnotatedTypeSymbol ResolvedType => new AnnotatedTypeSymbol(TypeInfo.Type.DisambiguateType(), TypeInfo.Nullability.Annotation); |
470 | | - public AnnotatedTypeSymbol ConvertedType => new AnnotatedTypeSymbol(TypeInfo.ConvertedType.DisambiguateType(), TypeInfo.ConvertedNullability.Annotation); |
471 | | - |
472 | | - private AnnotatedTypeSymbol? cachedType; |
473 | | - private bool cachedTypeSet; |
474 | | - public AnnotatedTypeSymbol? Type |
475 | | - { |
476 | | - get |
477 | | - { |
478 | | - if (cachedTypeSet) |
479 | | - return cachedType; |
480 | | - |
481 | | - var type = ResolvedType; |
482 | | - |
483 | | - if (type.Symbol == null) |
484 | | - type.Symbol = (TypeInfo.Type ?? TypeInfo.ConvertedType).DisambiguateType(); |
485 | | - |
486 | | - // Roslyn workaround: It can't work out the type of "new object[0]" |
487 | | - // Clearly a bug. |
488 | | - if (type.Symbol?.TypeKind == Microsoft.CodeAnalysis.TypeKind.Error) |
489 | | - { |
490 | | - if (Node is ArrayCreationExpressionSyntax arrayCreation) |
491 | | - { |
492 | | - var elementType = Context.GetType(arrayCreation.Type.ElementType); |
493 | | - |
494 | | - if (elementType.Symbol != null) |
495 | | - // There seems to be no way to create an array with a nullable element at present. |
496 | | - return new AnnotatedTypeSymbol(Context.Compilation.CreateArrayTypeSymbol(elementType.Symbol, arrayCreation.Type.RankSpecifiers.Count), NullableAnnotation.NotAnnotated); |
497 | | - } |
498 | | - |
499 | | - Context.ModelError(Node, "Failed to determine type"); |
500 | | - } |
501 | | - |
502 | | - cachedType = type; |
503 | | - cachedTypeSet = true; |
504 | | - |
505 | | - return type; |
506 | | - } |
507 | | - } |
508 | | - |
509 | | - private Microsoft.CodeAnalysis.Location location; |
510 | | - |
511 | | - public Microsoft.CodeAnalysis.Location CodeAnalysisLocation |
512 | | - { |
513 | | - get |
514 | | - { |
515 | | - if (location == null) |
516 | | - location = Node.FixedLocation(); |
517 | | - return location; |
518 | | - } |
519 | | - set |
520 | | - { |
521 | | - location = value; |
522 | | - } |
523 | | - } |
524 | | - |
525 | | - public SemanticModel Model => Context.GetModel(Node); |
526 | | - |
527 | | - public string ExprValue |
528 | | - { |
529 | | - get |
530 | | - { |
531 | | - var c = Model.GetConstantValue(Node); |
532 | | - if (c.HasValue) |
533 | | - { |
534 | | - return Expression.ValueAsString(c.Value); |
535 | | - } |
536 | | - |
537 | | - if (TryGetBoolValueFromLiteral(out var val)) |
538 | | - { |
539 | | - return Expression.ValueAsString(val); |
540 | | - } |
541 | | - |
542 | | - return null; |
543 | | - } |
544 | | - } |
545 | | - |
546 | | - private Extraction.Entities.Location cachedLocation; |
547 | | - |
548 | | - public Extraction.Entities.Location Location |
549 | | - { |
550 | | - get |
551 | | - { |
552 | | - if (cachedLocation == null) |
553 | | - cachedLocation = Context.Create(CodeAnalysisLocation); |
554 | | - return cachedLocation; |
555 | | - } |
556 | | - |
557 | | - set |
558 | | - { |
559 | | - cachedLocation = value; |
560 | | - } |
561 | | - } |
562 | | - |
563 | | - public ExprKind Kind { get; set; } = ExprKind.UNKNOWN; |
564 | | - |
565 | | - public bool IsCompilerGenerated { get; set; } |
566 | | - |
567 | | - public ExpressionNodeInfo SetParent(IExpressionParentEntity parent, int child) |
568 | | - { |
569 | | - Parent = parent; |
570 | | - Child = child; |
571 | | - return this; |
572 | | - } |
573 | | - |
574 | | - public ExpressionNodeInfo SetKind(ExprKind kind) |
575 | | - { |
576 | | - Kind = kind; |
577 | | - return this; |
578 | | - } |
579 | | - |
580 | | - public ExpressionNodeInfo SetType(AnnotatedTypeSymbol? type) |
581 | | - { |
582 | | - cachedType = type; |
583 | | - cachedTypeSet = true; |
584 | | - return this; |
585 | | - } |
586 | | - |
587 | | - public ExpressionNodeInfo SetNode(ExpressionSyntax node) |
588 | | - { |
589 | | - Node = node; |
590 | | - return this; |
591 | | - } |
592 | | - |
593 | | - private SymbolInfo cachedSymbolInfo; |
594 | | - |
595 | | - public SymbolInfo SymbolInfo |
596 | | - { |
597 | | - get |
598 | | - { |
599 | | - if (cachedSymbolInfo.Symbol == null && cachedSymbolInfo.CandidateReason == CandidateReason.None) |
600 | | - cachedSymbolInfo = Model.GetSymbolInfo(Node); |
601 | | - return cachedSymbolInfo; |
602 | | - } |
603 | | - } |
604 | | - |
605 | | - public NullableFlowState FlowState => TypeInfo.Nullability.FlowState; |
606 | | - |
607 | | - private bool TryGetBoolValueFromLiteral(out bool val) |
608 | | - { |
609 | | - var isTrue = Node.IsKind(SyntaxKind.TrueLiteralExpression); |
610 | | - var isFalse = Node.IsKind(SyntaxKind.FalseLiteralExpression); |
611 | | - |
612 | | - val = isTrue; |
613 | | - return isTrue || isFalse; |
614 | | - } |
615 | | - |
616 | | - public bool IsBoolLiteral() |
617 | | - { |
618 | | - return TryGetBoolValueFromLiteral(out var _); |
619 | | - } |
620 | | - } |
621 | 301 | } |
0 commit comments