Skip to content

Commit 70738f3

Browse files
committed
Fix NPEs around unresolved attribute references
Fixes #84
1 parent 0de27f8 commit 70738f3

File tree

4 files changed

+35
-11
lines changed

4 files changed

+35
-11
lines changed

delphi-checks/src/main/java/au/com/integradev/delphi/checks/ForbiddenRoutineCheck.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.sonar.plugins.communitydelphi.api.check.DelphiCheck;
3030
import org.sonar.plugins.communitydelphi.api.check.DelphiCheckContext;
3131
import org.sonar.plugins.communitydelphi.api.check.RuleTemplate;
32+
import org.sonar.plugins.communitydelphi.api.symbol.NameOccurrence;
3233
import org.sonar.plugins.communitydelphi.api.symbol.declaration.NameDeclaration;
3334
import org.sonar.plugins.communitydelphi.api.symbol.declaration.RoutineNameDeclaration;
3435
import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey;
@@ -70,10 +71,13 @@ public DelphiCheckContext visit(NameReferenceNode reference, DelphiCheckContext
7071

7172
@Override
7273
public DelphiCheckContext visit(AttributeNode attribute, DelphiCheckContext context) {
73-
NameDeclaration declaration = attribute.getConstructorNameOccurrence().getNameDeclaration();
74-
if (declaration instanceof RoutineNameDeclaration
75-
&& routinesSet.contains(((RoutineNameDeclaration) declaration).fullyQualifiedName())) {
76-
reportIssue(context, attribute.getNameReference().getIdentifier(), message);
74+
NameOccurrence occurrence = attribute.getConstructorNameOccurrence();
75+
if (occurrence != null) {
76+
NameDeclaration declaration = occurrence.getNameDeclaration();
77+
if (declaration instanceof RoutineNameDeclaration
78+
&& routinesSet.contains(((RoutineNameDeclaration) declaration).fullyQualifiedName())) {
79+
reportIssue(context, attribute.getNameReference().getIdentifier(), message);
80+
}
7781
}
7882
return super.visit(attribute, context);
7983
}

delphi-frontend/src/main/java/au/com/integradev/delphi/symbol/resolve/NameResolver.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,11 +548,15 @@ void readAttribute(AttributeNode node) {
548548
List<NameReferenceNode> references = node.getNameReference().flatten();
549549
NameReferenceNode lastReference = references.get(references.size() - 1);
550550

551+
var attributeNameOccurrence = (AttributeNameOccurrenceImpl) lastReference.getNameOccurrence();
552+
if (attributeNameOccurrence == null) {
553+
return;
554+
}
555+
551556
// Attributes are a shorthand for an invocation of a constructor named 'Create'
552557
SymbolicNode imaginaryConstructor = SymbolicNode.imaginary("Create", node.getScope());
553558
NameOccurrenceImpl occurrence = new NameOccurrenceImpl(imaginaryConstructor);
554-
((AttributeNameOccurrenceImpl) lastReference.getNameOccurrence())
555-
.setImplicitConstructorNameOccurrence(occurrence);
559+
attributeNameOccurrence.setImplicitConstructorNameOccurrence(occurrence);
556560

557561
resolveNameReferenceOccurrence(occurrence, true);
558562

delphi-frontend/src/main/java/au/com/integradev/delphi/type/factory/TypeFactoryImpl.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,15 @@
3636
import java.util.stream.Collectors;
3737
import javax.annotation.Nullable;
3838
import org.sonar.plugins.communitydelphi.api.ast.AttributeListNode;
39+
import org.sonar.plugins.communitydelphi.api.ast.AttributeNode;
3940
import org.sonar.plugins.communitydelphi.api.ast.ClassHelperTypeNode;
4041
import org.sonar.plugins.communitydelphi.api.ast.DelphiNode;
4142
import org.sonar.plugins.communitydelphi.api.ast.GenericDefinitionNode.TypeParameter;
4243
import org.sonar.plugins.communitydelphi.api.ast.HelperTypeNode;
4344
import org.sonar.plugins.communitydelphi.api.ast.Node;
4445
import org.sonar.plugins.communitydelphi.api.ast.TypeDeclarationNode;
4546
import org.sonar.plugins.communitydelphi.api.ast.TypeNode;
47+
import org.sonar.plugins.communitydelphi.api.symbol.declaration.NameDeclaration;
4648
import org.sonar.plugins.communitydelphi.api.symbol.declaration.TypeNameDeclaration;
4749
import org.sonar.plugins.communitydelphi.api.symbol.declaration.TypedDeclaration;
4850
import org.sonar.plugins.communitydelphi.api.symbol.scope.DelphiScope;
@@ -68,7 +70,6 @@
6870
import org.sonar.plugins.communitydelphi.api.type.Type.StructType;
6971
import org.sonar.plugins.communitydelphi.api.type.Type.SubrangeType;
7072
import org.sonar.plugins.communitydelphi.api.type.TypeFactory;
71-
import org.sonar.plugins.communitydelphi.api.type.Typed;
7273

7374
public class TypeFactoryImpl implements TypeFactory {
7475
private static final CompilerVersion VERSION_4 = CompilerVersion.fromVersionSymbol("VER120");
@@ -505,10 +506,21 @@ private static List<Type> getAttributeTypes(TypeDeclarationNode typeDeclaration)
505506
}
506507

507508
return attributeList.getAttributes().stream()
508-
.map(attribute -> attribute.getTypeNameOccurrence().getNameDeclaration())
509-
.map(TypeNameDeclaration.class::cast)
510-
.map(Typed::getType)
511-
.collect(Collectors.toList());
509+
.map(AttributeNode::getTypeNameOccurrence)
510+
.map(
511+
occurrence -> {
512+
if (occurrence == null) {
513+
return TypeFactory.unknownType();
514+
}
515+
516+
NameDeclaration declaration = occurrence.getNameDeclaration();
517+
if (!(declaration instanceof TypeNameDeclaration)) {
518+
return TypeFactory.unknownType();
519+
}
520+
521+
return ((TypeNameDeclaration) declaration).getType();
522+
})
523+
.collect(Collectors.toUnmodifiableList());
512524
}
513525

514526
public HelperType helper(HelperTypeNode node) {

delphi-frontend/src/main/java/org/sonar/plugins/communitydelphi/api/ast/AttributeNode.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@
1818
*/
1919
package org.sonar.plugins.communitydelphi.api.ast;
2020

21+
import javax.annotation.Nullable;
2122
import org.sonar.plugins.communitydelphi.api.symbol.NameOccurrence;
2223

2324
public interface AttributeNode extends DelphiNode {
2425
NameReferenceNode getNameReference();
2526

27+
@Nullable
2628
NameOccurrence getTypeNameOccurrence();
2729

30+
@Nullable
2831
NameOccurrence getConstructorNameOccurrence();
2932

33+
@Nullable
3034
ArgumentListNode getArgumentList();
3135
}

0 commit comments

Comments
 (0)