]> source.dussan.org Git - aspectj.git/blob
c42a503c6137ac3e5dafa987e46bb6553a64cd7d
[aspectj.git] /
1 /* *******************************************************************
2  * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
3  * All rights reserved. 
4  * This program and the accompanying materials are made available 
5  * under the terms of the Eclipse Public License v1.0 
6  * which accompanies this distribution and is available at 
7  * http://www.eclipse.org/legal/epl-v10.html 
8  *  
9  * Contributors: 
10  *     PARC     initial implementation 
11  * ******************************************************************/
12
13 package org.aspectj.ajdt.internal.compiler.problem;
14
15 import java.io.PrintWriter;
16 import java.io.StringWriter;
17 import java.lang.reflect.Modifier;
18 import java.util.Collection;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Set;
23
24 import org.aspectj.ajdt.internal.compiler.ast.AdviceDeclaration;
25 import org.aspectj.ajdt.internal.compiler.ast.AspectDeclaration;
26 import org.aspectj.ajdt.internal.compiler.ast.DeclareAnnotationDeclaration;
27 import org.aspectj.ajdt.internal.compiler.ast.IfMethodDeclaration;
28 import org.aspectj.ajdt.internal.compiler.ast.PointcutDeclaration;
29 import org.aspectj.ajdt.internal.compiler.ast.Proceed;
30 import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
31 import org.aspectj.ajdt.internal.compiler.lookup.InterTypeMethodBinding;
32 import org.aspectj.ajdt.internal.compiler.lookup.PrivilegedFieldBinding;
33 import org.aspectj.bridge.context.CompilationAndWeavingContext;
34 import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
35 import org.aspectj.org.eclipse.jdt.core.compiler.IProblem;
36 import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
37 import org.aspectj.org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
38 import org.aspectj.org.eclipse.jdt.internal.compiler.IProblemFactory;
39 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ASTNode;
40 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
41 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
42 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
43 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
44 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression;
45 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
46 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
47 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
48 import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
49 import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
50 import org.aspectj.org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
51 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
52 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.IPrivilegedHandler;
53 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
54 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
55 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding;
56 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
57 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Scope;
58 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
59 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TagBits;
60 import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
61 import org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
62 import org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
63 import org.aspectj.util.FuzzyBoolean;
64 import org.aspectj.weaver.AjcMemberMaker;
65 import org.aspectj.weaver.ConcreteTypeMunger;
66 import org.aspectj.weaver.ReferenceType;
67 import org.aspectj.weaver.ResolvedMember;
68 import org.aspectj.weaver.ResolvedType;
69 import org.aspectj.weaver.ResolvedTypeMunger;
70 import org.aspectj.weaver.Shadow;
71 import org.aspectj.weaver.UnresolvedType;
72 import org.aspectj.weaver.patterns.Declare;
73 import org.aspectj.weaver.patterns.DeclareAnnotation;
74 import org.aspectj.weaver.patterns.DeclareParents;
75 import org.aspectj.weaver.patterns.DeclareSoft;
76 import org.aspectj.weaver.patterns.TypePattern;
77
78 /**
79  * Extends problem reporter to support compiler-side implementation of declare soft. Also overrides error reporting for the need to
80  * implement abstract methods to account for inter-type declarations and pointcut declarations. This second job might be better done
81  * directly in the SourceTypeBinding/ClassScope classes.
82  * 
83  * @author Jim Hugunin
84  */
85 public class AjProblemReporter extends ProblemReporter {
86
87         private static final boolean DUMP_STACK = false;
88
89         public EclipseFactory factory;
90
91         public AjProblemReporter(IErrorHandlingPolicy policy, CompilerOptions options, IProblemFactory problemFactory) {
92                 super(policy, options, problemFactory);
93         }
94
95         public void unhandledException(TypeBinding exceptionType, ASTNode location) {
96                 if (!factory.getWorld().getDeclareSoft().isEmpty()) {
97                         Shadow callSite = factory.makeShadow(location, referenceContext);
98                         Shadow enclosingExec = factory.makeShadow(referenceContext);
99                         // PR 72157 - calls to super / this within a constructor are not part of the cons join point.
100                         if ((callSite == null) && (enclosingExec.getKind() == Shadow.ConstructorExecution)
101                                         && (location instanceof ExplicitConstructorCall)) {
102                                 super.unhandledException(exceptionType, location);
103                                 return;
104                         }
105                         // System.err.println("about to show error for unhandled exception: " + new String(exceptionType.sourceName()) +
106                         // " at " + location + " in " + referenceContext);
107
108                         for (DeclareSoft d: factory.getWorld().getDeclareSoft()) {
109 //                      for (Iterator<DeclareSoft> i = factory.getWorld().getDeclareSoft().iterator(); i.hasNext();) {
110 //                              DeclareSoft d = (DeclareSoft) i.next();
111                                 // We need the exceptionType to match the type in the declare soft statement
112                                 // This means it must either be the same type or a subtype
113                                 ResolvedType throwException = factory.fromEclipse((ReferenceBinding) exceptionType);
114                                 FuzzyBoolean isExceptionTypeOrSubtype = d.getException().matchesInstanceof(throwException);
115                                 if (!isExceptionTypeOrSubtype.alwaysTrue())
116                                         continue;
117
118                                 if (callSite != null) {
119                                         FuzzyBoolean match = d.getPointcut().match(callSite);
120                                         if (match.alwaysTrue()) {
121                                                 // System.err.println("matched callSite: " + callSite + " with " + d);
122                                                 return;
123                                         } else if (!match.alwaysFalse()) {
124                                                 // !!! need this check to happen much sooner
125                                                 // throw new RuntimeException("unimplemented, shouldn't have fuzzy match here");
126                                         }
127                                 }
128                                 if (enclosingExec != null) {
129                                         FuzzyBoolean match = d.getPointcut().match(enclosingExec);
130                                         if (match.alwaysTrue()) {
131                                                 // System.err.println("matched enclosingExec: " + enclosingExec + " with " + d);
132                                                 return;
133                                         } else if (!match.alwaysFalse()) {
134                                                 // !!! need this check to happen much sooner
135                                                 // throw new RuntimeException("unimplemented, shouldn't have fuzzy match here");
136                                         }
137                                 }
138                         }
139                 }
140
141                 // ??? is this always correct
142                 if (location instanceof Proceed) {
143                         return;
144                 }
145
146                 super.unhandledException(exceptionType, location);
147         }
148         
149         public void unhandledExceptionFromAutoClose(TypeBinding exceptionType, ASTNode location) {
150                 if (!factory.getWorld().getDeclareSoft().isEmpty()) {
151                         Shadow callSite = factory.makeShadow(location, referenceContext);
152                         Shadow enclosingExec = factory.makeShadow(referenceContext);
153                         // PR 72157 - calls to super / this within a constructor are not part of the cons join point.
154                         if ((callSite == null) && (enclosingExec.getKind() == Shadow.ConstructorExecution)
155                                         && (location instanceof ExplicitConstructorCall)) {
156                                 super.unhandledException(exceptionType, location);
157                                 return;
158                         }
159                         // System.err.println("about to show error for unhandled exception: " + new String(exceptionType.sourceName()) +
160                         // " at " + location + " in " + referenceContext);
161
162                         for (DeclareSoft d: factory.getWorld().getDeclareSoft()) {
163 //                      for (Iterator<DeclareSoft> i = factory.getWorld().getDeclareSoft().iterator(); i.hasNext();) {
164 //                              DeclareSoft d = (DeclareSoft) i.next();
165                                 // We need the exceptionType to match the type in the declare soft statement
166                                 // This means it must either be the same type or a subtype
167                                 ResolvedType throwException = factory.fromEclipse((ReferenceBinding) exceptionType);
168                                 FuzzyBoolean isExceptionTypeOrSubtype = d.getException().matchesInstanceof(throwException);
169                                 if (!isExceptionTypeOrSubtype.alwaysTrue())
170                                         continue;
171
172                                 if (callSite != null) {
173                                         FuzzyBoolean match = d.getPointcut().match(callSite);
174                                         if (match.alwaysTrue()) {
175                                                 // System.err.println("matched callSite: " + callSite + " with " + d);
176                                                 return;
177                                         } else if (!match.alwaysFalse()) {
178                                                 // !!! need this check to happen much sooner
179                                                 // throw new RuntimeException("unimplemented, shouldn't have fuzzy match here");
180                                         }
181                                 }
182                                 if (enclosingExec != null) {
183                                         FuzzyBoolean match = d.getPointcut().match(enclosingExec);
184                                         if (match.alwaysTrue()) {
185                                                 // System.err.println("matched enclosingExec: " + enclosingExec + " with " + d);
186                                                 return;
187                                         } else if (!match.alwaysFalse()) {
188                                                 // !!! need this check to happen much sooner
189                                                 // throw new RuntimeException("unimplemented, shouldn't have fuzzy match here");
190                                         }
191                                 }
192                         }
193                 }
194
195                 // ??? is this always correct
196                 if (location instanceof Proceed) {
197                         return;
198                 }
199
200                 super.unhandledExceptionFromAutoClose(exceptionType, location);
201         }
202
203         private boolean isPointcutDeclaration(MethodBinding binding) {
204                 return CharOperation.prefixEquals(PointcutDeclaration.mangledPrefix, binding.selector);
205         }
206
207         private boolean isIntertypeDeclaration(MethodBinding binding) {
208                 return (binding instanceof InterTypeMethodBinding);
209         }
210
211         public void abstractMethodCannotBeOverridden(SourceTypeBinding type, MethodBinding concreteMethod) {
212                 if (isPointcutDeclaration(concreteMethod)) {
213                         return;
214                 }
215                 super.abstractMethodCannotBeOverridden(type, concreteMethod);
216         }
217
218         public void inheritedMethodReducesVisibility(SourceTypeBinding type, MethodBinding concreteMethod,
219                         MethodBinding[] abstractMethods) {
220                 // if we implemented this method by a public inter-type declaration, then there is no error
221
222                 ResolvedType onTypeX = null;
223                 // If the type is anonymous, look at its supertype
224                 if (!type.isAnonymousType()) {
225                         onTypeX = factory.fromEclipse(type);
226                 } else {
227                         // Hmmm. If the ITD is on an interface that is being 'instantiated' using an anonymous type,
228                         // we sort it out elsewhere and don't come into this method -
229                         // so we don't have to worry about interfaces, just the superclass.
230                         onTypeX = factory.fromEclipse(type.superclass()); // abstractMethod.declaringClass);
231                 }
232                 for (ConcreteTypeMunger m : onTypeX.getInterTypeMungersIncludingSupers()) {
233                         ResolvedMember sig = m.getSignature();
234                         if (!Modifier.isAbstract(sig.getModifiers())) {
235                                 if (ResolvedType.matches(
236                                                 AjcMemberMaker.interMethod(sig, m.getAspectType(), sig.getDeclaringType().resolve(factory.getWorld())
237                                                                 .isInterface()), factory.makeResolvedMember(concreteMethod))) {
238                                         return;
239                                 }
240                         }
241                 }
242
243                 super.inheritedMethodReducesVisibility(type, concreteMethod, abstractMethods);
244         }
245
246         // if either of the MethodBinding is an ITD, we have already reported it.
247         public void staticAndInstanceConflict(MethodBinding currentMethod, MethodBinding inheritedMethod) {
248                 if (currentMethod instanceof InterTypeMethodBinding)
249                         return;
250                 if (inheritedMethod instanceof InterTypeMethodBinding)
251                         return;
252                 super.staticAndInstanceConflict(currentMethod, inheritedMethod);
253         }
254
255         public void abstractMethodMustBeImplemented(SourceTypeBinding type, MethodBinding abstractMethod) {
256                 // if this is a PointcutDeclaration then there is no error
257                 if (isPointcutDeclaration(abstractMethod))
258                         return;
259
260                 if (isIntertypeDeclaration(abstractMethod))
261                         return; // when there is a problem with an ITD not being implemented, it will be reported elsewhere
262
263                 if (CharOperation.prefixEquals("ajc$interField".toCharArray(), abstractMethod.selector)) {
264                         // ??? think through how this could go wrong
265                         return;
266                 }
267
268                 // if we implemented this method by an inter-type declaration, then there is no error
269                 // ??? be sure this is always right
270                 ResolvedType onTypeX = null;
271
272                 // If the type is anonymous, look at its supertype
273                 if (!type.isAnonymousType()) {
274                         onTypeX = factory.fromEclipse(type);
275                 } else {
276                         // Hmmm. If the ITD is on an interface that is being 'instantiated' using an anonymous type,
277                         // we sort it out elsewhere and don't come into this method -
278                         // so we don't have to worry about interfaces, just the superclass.
279                         onTypeX = factory.fromEclipse(type.superclass()); // abstractMethod.declaringClass);
280                 }
281
282                 if (onTypeX.isRawType())
283                         onTypeX = onTypeX.getGenericType();
284
285                 List<ConcreteTypeMunger> mungers = onTypeX.getInterTypeMungersIncludingSupers();
286                 for (ConcreteTypeMunger m : mungers) {
287                         ResolvedMember sig = m.getSignature();
288                         if (sig != null && !Modifier.isAbstract(sig.getModifiers())) {
289                                 ResolvedMember abstractMember = factory.makeResolvedMember(abstractMethod);
290                                 if (abstractMember.getName().startsWith("ajc$interMethodDispatch")) {
291                                         ResolvedType dType = factory.getWorld().resolve(sig.getDeclaringType(), false);
292                                         if (ResolvedType.matches(AjcMemberMaker.interMethod(sig, m.getAspectType(), dType.isInterface()),
293                                                         abstractMember)) {
294                                                 return;
295                                         }
296                                 } else {
297                                         // In this case we have something like:
298                                         // interface I {}
299                                         // abstract class C implements I { abstract void foo();}
300                                         // class D extends C {}
301                                         // ITD: public void I.foo() {...}
302                                         // The ITD is providing the implementation of foo in the class D but when checking for whether the abstract
303                                         // method is overridden, we won't be looking at whether the ITD overrides ajc$interMethodDispath$...foo but
304                                         // whether it overrides the foo method from class C
305                                         if (ResolvedType.matches(sig, factory.makeResolvedMember(abstractMethod)))
306                                                 return;
307                                 }
308                         }
309                 }
310
311                 super.abstractMethodMustBeImplemented(type, abstractMethod);
312         }
313
314         /*
315          * (non-Javadoc)
316          * 
317          * @see
318          * org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemReporter#disallowedTargetForAnnotation(org.aspectj.org.eclipse
319          * .jdt.internal.compiler.ast.Annotation)
320          */
321         public void disallowedTargetForAnnotation(Annotation annotation) {
322                 // if the annotation's recipient is an ITD, it might be allowed after all...
323                 if (annotation.recipient instanceof MethodBinding) {
324                         MethodBinding binding = (MethodBinding) annotation.recipient;
325                         String name = new String(binding.selector);
326                         if (name.startsWith("ajc$")) {
327                                 long metaTagBits = annotation.resolvedType.getAnnotationTagBits(); // could be forward reference
328                                 if (name.contains("interField")) {
329                                         if ((metaTagBits & TagBits.AnnotationForField) != 0)
330                                                 return;
331                                 } else if (name.contains("interConstructor")) {
332                                         if ((metaTagBits & TagBits.AnnotationForConstructor) != 0)
333                                                 return;
334                                 } else if (name.contains("interMethod")) {
335                                         if ((metaTagBits & TagBits.AnnotationForMethod) != 0)
336                                                 return;
337                                 } else if (name.contains("declare_" + DeclareAnnotation.AT_TYPE + "_")) {
338                                         if ((metaTagBits & TagBits.AnnotationForAnnotationType) != 0 || (metaTagBits & TagBits.AnnotationForType) != 0)
339                                                 return;
340                                 } else if (name.contains("declare_" + DeclareAnnotation.AT_FIELD + "_")) {
341                                         if ((metaTagBits & TagBits.AnnotationForField) != 0)
342                                                 return;
343                                 } else if (name.contains("declare_" + DeclareAnnotation.AT_CONSTRUCTOR + "_")) {
344                                         if ((metaTagBits & TagBits.AnnotationForConstructor) != 0)
345                                                 return;
346                                 } else if (name.contains("declare_eow")) {
347                                         if ((metaTagBits & TagBits.AnnotationForField) != 0)
348                                                 return;
349                                 }
350                         }
351                 }
352
353                 // not our special case, report the problem...
354                 super.disallowedTargetForAnnotation(annotation);
355         }
356
357         public void overridesPackageDefaultMethod(MethodBinding localMethod, MethodBinding inheritedMethod) {
358                 if (new String(localMethod.selector).startsWith("ajc$"))
359                         return;
360                 super.overridesPackageDefaultMethod(localMethod, inheritedMethod);
361         }
362
363         public void handle(int problemId, String[] problemArguments, String[] messageArguments, int severity, int problemStartPosition,
364                         int problemEndPosition, ReferenceContext referenceContext, CompilationResult unitResult) {
365                 if (severity != ProblemSeverities.Ignore && DUMP_STACK) {
366                         Thread.dumpStack();
367                 }
368                 super.handle(problemId, problemArguments, 
369                                 0, // no message elaboration
370                                 messageArguments, severity, problemStartPosition, problemEndPosition,
371                                 referenceContext, unitResult);
372         }
373
374         // PR71076
375         public void javadocMissingParamTag(char[] name, int sourceStart, int sourceEnd, int modifiers) {
376                 boolean reportIt = true;
377                 String sName = new String(name);
378                 if (sName.startsWith("ajc$"))
379                         reportIt = false;
380                 if (sName.equals("thisJoinPoint"))
381                         reportIt = false;
382                 if (sName.equals("thisJoinPointStaticPart"))
383                         reportIt = false;
384                 if (sName.equals("thisEnclosingJoinPointStaticPart"))
385                         reportIt = false;
386                 if (sName.equals("ajc_aroundClosure"))
387                         reportIt = false;
388                 if (reportIt)
389                         super.javadocMissingParamTag(name, sourceStart, sourceEnd, modifiers);
390         }
391
392         public void abstractMethodInAbstractClass(SourceTypeBinding type, AbstractMethodDeclaration methodDecl) {
393
394                 String abstractMethodName = new String(methodDecl.selector);
395                 if (abstractMethodName.startsWith("ajc$pointcut")) {
396                         // This will already have been reported, see: PointcutDeclaration.postParse()
397                         return;
398                 }
399                 String[] arguments = new String[] { new String(type.sourceName()), abstractMethodName };
400                 super.handle(IProblem.AbstractMethodInAbstractClass, arguments, arguments, methodDecl.sourceStart, methodDecl.sourceEnd,
401                                 this.referenceContext, this.referenceContext == null ? null : this.referenceContext.compilationResult());
402         }
403
404         /**
405          * Called when there is an ITD marked @override that doesn't override a supertypes method. The method and the binding are passed
406          * - some information is useful from each. The 'method' knows about source offsets for the message, the 'binding' has the
407          * signature of what the ITD is trying to be in the target class.
408          */
409         public void itdMethodMustOverride(AbstractMethodDeclaration method, MethodBinding binding) {
410                 this.handle(IProblem.MethodMustOverride,
411                                 new String[] { new String(binding.selector), typesAsString(binding.isVarargs(), binding.parameters, false),
412                                                 new String(binding.declaringClass.readableName()), },
413                                 new String[] { new String(binding.selector), typesAsString(binding.isVarargs(), binding.parameters, true),
414                                                 new String(binding.declaringClass.shortReadableName()), }, method.sourceStart, method.sourceEnd,
415                                 this.referenceContext, this.referenceContext == null ? null : this.referenceContext.compilationResult());
416         }
417
418         /**
419          * Overrides the implementation in ProblemReporter and is ITD aware. To report a *real* problem with an ITD marked @override,
420          * the other methodMustOverride() method is used.
421          */
422         public void methodMustOverride(AbstractMethodDeclaration method, long complianceLevel) {
423
424                 // ignore ajc$ methods
425                 if (new String(method.selector).startsWith("ajc$"))
426                         return;
427                 ResolvedMember possiblyErroneousRm = factory.makeResolvedMember(method.binding);
428
429                 ResolvedType onTypeX = factory.fromEclipse(method.binding.declaringClass);
430                 // Can't use 'getInterTypeMungersIncludingSupers()' since that will exclude abstract ITDs
431                 // on any super classes - so we have to trawl up ourselves.. I wonder if this problem
432                 // affects other code in the problem reporter that looks through ITDs...
433                 ResolvedType supertypeToLookAt = onTypeX.getSuperclass();
434                 while (supertypeToLookAt != null) {
435                         List<ConcreteTypeMunger> itMungers = supertypeToLookAt.getInterTypeMungers();
436                         for (ConcreteTypeMunger m : itMungers) {
437                                 if (m.getMunger() != null && m.getMunger().getKind() == ResolvedTypeMunger.PrivilegedAccess) {
438                                         continue;
439                                 }
440                                 ResolvedMember sig = m.getSignature();
441                                 if (sig == null)
442                                         continue; // we aren't interested in other kinds of munger
443                                 UnresolvedType dType = sig.getDeclaringType();
444                                 if (dType == null)
445                                         continue;
446                                 ResolvedType resolvedDeclaringType = dType.resolve(factory.getWorld());
447                                 ResolvedMember rm = AjcMemberMaker.interMethod(sig, m.getAspectType(), resolvedDeclaringType.isInterface());
448                                 if (ResolvedType.matches(rm, possiblyErroneousRm)) {
449                                         // match, so dont need to report a problem!
450                                         return;
451                                 }
452                         }
453                         supertypeToLookAt = supertypeToLookAt.getSuperclass();
454                 }
455                 // report the error...
456                 super.methodMustOverride(method,complianceLevel);
457         }
458
459         private String typesAsString(boolean isVarargs, TypeBinding[] types, boolean makeShort) {
460                 StringBuffer buffer = new StringBuffer(10);
461                 for (int i = 0, length = types.length; i < length; i++) {
462                         if (i != 0)
463                                 buffer.append(", "); //$NON-NLS-1$
464                         TypeBinding type = types[i];
465                         boolean isVarargType = isVarargs && i == length - 1;
466                         if (isVarargType)
467                                 type = ((ArrayBinding) type).elementsType();
468                         buffer.append(new String(makeShort ? type.shortReadableName() : type.readableName()));
469                         if (isVarargType)
470                                 buffer.append("..."); //$NON-NLS-1$
471                 }
472                 return buffer.toString();
473         }
474
475         public void visibilityConflict(MethodBinding currentMethod, MethodBinding inheritedMethod) {
476                 // Not quite sure if the conditions on this test are right - basically I'm saying
477                 // DONT WORRY if its ITDs since the error will be reported another way...
478                 if (isIntertypeDeclaration(currentMethod) && isIntertypeDeclaration(inheritedMethod)
479                                 && Modifier.isPrivate(currentMethod.modifiers) && Modifier.isPrivate(inheritedMethod.modifiers)) {
480                         return;
481                 }
482                 super.visibilityConflict(currentMethod, inheritedMethod);
483         }
484
485         public void unusedPrivateType(TypeDeclaration typeDecl) {
486                 // don't output unused type warnings for aspects!
487                 if (typeDecl instanceof AspectDeclaration)
488                         return;
489                 if (typeDecl.enclosingType != null && (typeDecl.enclosingType instanceof AspectDeclaration)) {
490                         AspectDeclaration ad = (AspectDeclaration) typeDecl.enclosingType;
491                         if (ad.concreteName != null) {
492                                 List<Declare> declares = ad.concreteName.declares;
493                                 for (Object dec : declares) {
494                                         if (dec instanceof DeclareParents) {
495                                                 DeclareParents decp = (DeclareParents) dec;
496                                                 TypePattern[] newparents = decp.getParents().getTypePatterns();
497                                                 for (TypePattern pattern : newparents) {
498                                                         UnresolvedType ut = pattern.getExactType();
499                                                         if (ut == null)
500                                                                 continue;
501                                                         if (CharOperation.compareWith(typeDecl.binding.signature(), ut.getSignature().toCharArray()) == 0)
502                                                                 return;
503                                                 }
504                                         }
505                                 }
506                         }
507                 }
508                 super.unusedPrivateType(typeDecl);
509         }
510         
511         private final static char[] thisJoinPointName = "thisJoinPoint".toCharArray();
512         private final static char[] thisJoinPointStaticPartName = "thisJoinPointStaticPart".toCharArray();
513         private final static char[] thisEnclosingJoinPointStaticPartName = "thisEnclosingJoinPointStaticPart".toCharArray();
514         private final static char[] thisAspectInstanceName = "thisAspectInstance".toCharArray();
515
516         @Override
517         public void uninitializedLocalVariable(LocalVariableBinding binding, ASTNode location, Scope scope) {
518                 if (CharOperation.equals(binding.name, thisJoinPointName) ||
519                         CharOperation.equals(binding.name, thisJoinPointStaticPartName) ||
520                         CharOperation.equals(binding.name, thisAspectInstanceName) || 
521                         CharOperation.equals(binding.name, thisEnclosingJoinPointStaticPartName)) {
522                         // If in advice, this is not a problem
523                         if (binding.declaringScope!=null && (binding.declaringScope.referenceContext() instanceof AdviceDeclaration ||
524                                                                                                  binding.declaringScope.referenceContext() instanceof IfMethodDeclaration)) {
525                                 return;
526                         }
527                 }                       
528                 super.uninitializedLocalVariable(binding, location, scope);
529         }
530         
531         public void abstractMethodInConcreteClass(SourceTypeBinding type) {
532                 if (type.scope!=null && type.scope.referenceContext instanceof AspectDeclaration) {
533                         // TODO could put out an Aspect specific message here
534                         return;
535                 } 
536                 super.abstractMethodInConcreteClass(type);
537         }
538
539         // Don't warn if there is an ITD method/ctor from a privileged aspect
540         public void unusedPrivateField(FieldDeclaration fieldDecl) {
541                 if (fieldDecl!=null && fieldDecl.binding != null && fieldDecl.binding.declaringClass != null) {
542                         ReferenceBinding type = fieldDecl.binding.declaringClass;
543
544                         ResolvedType weaverType = null;
545                         if (!type.isAnonymousType()) {
546                                 weaverType = factory.fromEclipse(type);
547                         } else {
548                                 weaverType = factory.fromEclipse(type.superclass());
549                         }
550                         Set checked = new HashSet();
551                         for (ConcreteTypeMunger m : weaverType.getInterTypeMungersIncludingSupers()) {
552                                 ResolvedType theAspect = m.getAspectType();
553                                 if (!checked.contains(theAspect)) {
554                                         TypeBinding tb = factory.makeTypeBinding(m.getAspectType());
555                                         // Let's check the privilegedHandler from that aspect
556                                         if (tb instanceof SourceTypeBinding) { // BinaryTypeBinding is also a SourceTypeBinding ;)
557                                                 IPrivilegedHandler privilegedHandler = ((SourceTypeBinding) tb).privilegedHandler;
558                                                 if (privilegedHandler != null) {
559                                                         if (privilegedHandler.definesPrivilegedAccessToField(fieldDecl.binding)) {
560                                                                 return;
561                                                         }
562                                                 } else if (theAspect instanceof ReferenceType) {
563                                                         // ResolvedMember rm = factory.makeResolvedMember(fieldDecl.binding);
564                                                         String fname = new String(fieldDecl.name);
565                                                         Collection/* ResolvedMember */privvies = ((ReferenceType) theAspect).getPrivilegedAccesses();
566                                                         // On an incremental compile the information is in the bcel delegate
567                                                         if (privvies != null) {
568                                                                 for (Object privvy : privvies) {
569                                                                         ResolvedMember priv = (ResolvedMember) privvy;
570                                                                         if (priv.getName().equals(fname)) {
571                                                                                 return;
572                                                                         }
573                                                                 }
574                                                         }
575                                                 }
576                                         }
577                                         checked.add(theAspect);
578                                 }
579                         }
580                 }
581                 super.unusedPrivateField(fieldDecl);
582         }
583
584         public void unusedPrivateMethod(AbstractMethodDeclaration methodDecl) {
585                 // don't output unused warnings for pointcuts...
586                 if (!(methodDecl instanceof PointcutDeclaration))
587                         super.unusedPrivateMethod(methodDecl);
588         }
589
590         public void caseExpressionMustBeConstant(Expression expression) {
591                 if (expression instanceof QualifiedNameReference) {
592                         QualifiedNameReference qnr = (QualifiedNameReference) expression;
593                         if (qnr.otherBindings != null && qnr.otherBindings.length > 0 && qnr.otherBindings[0] instanceof PrivilegedFieldBinding) {
594                                 super.signalError(expression.sourceStart, expression.sourceEnd,
595                                                 "Fields accessible due to an aspect being privileged can not be used in switch statements");
596                                 referenceContext.tagAsHavingErrors();
597                                 return;
598                         }
599                 }
600                 super.caseExpressionMustBeConstant(expression);
601         }
602
603         public void unusedArgument(LocalDeclaration localDecl) {
604                 // don't warn if this is an aj synthetic arg
605                 String argType = new String(localDecl.type.resolvedType.signature());
606                 if (argType.startsWith("Lorg/aspectj/runtime/internal"))
607                         return;
608
609                 // If the unused argument is in a pointcut, don't report the problem (for now... pr148219)
610                 if (localDecl instanceof Argument) {
611                         Argument arg = (Argument) localDecl;
612                         if (arg.binding != null && arg.binding.declaringScope != null) {
613                                 ReferenceContext context = arg.binding.declaringScope.referenceContext();
614                                 if (context != null && context instanceof PointcutDeclaration)
615                                         return;
616                         }
617                 }
618                 if (new String(localDecl.name).startsWith("ajc$")) {
619                         // Do not report problems for infrastructure variables beyond the users control - pr195090
620                         return;
621                 }
622                 super.unusedArgument(localDecl);
623         }
624
625         /**
626          * A side-effect of the way that we handle itds on default methods on top-most implementors of interfaces is that a class
627          * acquiring a final default ITD will erroneously report that it can't override its own member. This method detects that
628          * situation.
629          */
630         public void finalMethodCannotBeOverridden(MethodBinding currentMethod, MethodBinding inheritedMethod) {
631                 if (currentMethod == inheritedMethod)
632                         return;
633                 super.finalMethodCannotBeOverridden(currentMethod, inheritedMethod);
634         }
635
636         /**
637          * The method verifier is a bit 'keen' and doesn't cope well with ITDMs which are of course to be considered a 'default'
638          * implementation if the target type doesn't supply one. This test may not be complete - it is possible that it should read if
639          * *either* is an ITD...but I dont have a testcase that shows that is required. yet. (pr115788)
640          */
641         public void duplicateInheritedMethods(SourceTypeBinding type, MethodBinding inheritedMethod1, MethodBinding inheritedMethod2, boolean isJava8) {
642                 if (inheritedMethod1 instanceof InterTypeMethodBinding || inheritedMethod2 instanceof InterTypeMethodBinding)
643                         return;
644                 if ((inheritedMethod1 instanceof ParameterizedMethodBinding)
645                                 && ((ParameterizedMethodBinding) inheritedMethod1).original() instanceof InterTypeMethodBinding)
646                         return;
647                 if ((inheritedMethod2 instanceof ParameterizedMethodBinding)
648                                 && ((ParameterizedMethodBinding) inheritedMethod2).original() instanceof InterTypeMethodBinding)
649                         return;
650                 super.duplicateInheritedMethods(type, inheritedMethod1, inheritedMethod2, isJava8);
651         }
652
653         /**
654          * All problems end up routed through here at some point...
655          */
656         public IProblem createProblem(char[] fileName, int problemId, String[] problemArguments, String[] messageArguments,
657                         int severity, int problemStartPosition, int problemEndPosition, int lineNumber) {
658                 IProblem problem = super.createProblem(fileName, problemId, problemArguments, messageArguments, severity,
659                                 problemStartPosition, problemEndPosition, lineNumber, 0);
660                 if (factory.getWorld().isInPinpointMode()) {
661                         MessageIssued ex = new MessageIssued();
662                         ex.fillInStackTrace();
663                         StringWriter sw = new StringWriter();
664                         ex.printStackTrace(new PrintWriter(sw));
665                         StringBuffer sb = new StringBuffer();
666                         sb.append(CompilationAndWeavingContext.getCurrentContext());
667                         sb.append(sw.toString());
668                         problem = new PinpointedProblem(problem, sb.toString());
669                 }
670                 return problem;
671         }
672
673         private static class MessageIssued extends RuntimeException {
674                 public String getMessage() {
675                         return "message issued...";
676                 }
677         }
678
679         private static class PinpointedProblem implements IProblem {
680
681                 private IProblem delegate;
682                 private String message;
683
684                 public PinpointedProblem(IProblem aProblem, String pinpoint) {
685                         this.delegate = aProblem;
686                         // if this was a problem that came via the weaver, it will already have
687                         // pinpoint info, don't do it twice...
688                         if (!delegate.getMessage().contains("message issued...")) {
689                                 this.message = delegate.getMessage() + "\n" + pinpoint;
690                         } else {
691                                 this.message = delegate.getMessage();
692                         }
693                 }
694
695                 public String[] getArguments() {
696                         return delegate.getArguments();
697                 }
698
699                 public int getID() {
700                         return delegate.getID();
701                 }
702
703                 public String getMessage() {
704                         return message;
705                 }
706
707                 public char[] getOriginatingFileName() {
708                         return delegate.getOriginatingFileName();
709                 }
710
711                 public int getSourceEnd() {
712                         return delegate.getSourceEnd();
713                 }
714
715                 public int getSourceLineNumber() {
716                         return delegate.getSourceLineNumber();
717                 }
718
719                 public int getSourceStart() {
720                         return delegate.getSourceStart();
721                 }
722
723                 public boolean isError() {
724                         return delegate.isError();
725                 }
726
727                 public boolean isWarning() {
728                         return delegate.isWarning();
729                 }
730
731                 public void setSourceEnd(int sourceEnd) {
732                         delegate.setSourceEnd(sourceEnd);
733                 }
734
735                 public void setSourceLineNumber(int lineNumber) {
736                         delegate.setSourceLineNumber(lineNumber);
737                 }
738
739                 public void setSourceStart(int sourceStart) {
740                         delegate.setSourceStart(sourceStart);
741                 }
742
743                 public void setSeeAlsoProblems(IProblem[] problems) {
744                         delegate.setSeeAlsoProblems(problems);
745                 }
746
747                 public IProblem[] seeAlso() {
748                         return delegate.seeAlso();
749                 }
750
751                 public void setSupplementaryMessageInfo(String msg) {
752                         delegate.setSupplementaryMessageInfo(msg);
753                 }
754
755                 public String getSupplementaryMessageInfo() {
756                         return delegate.getSupplementaryMessageInfo();
757                 }
758
759                 @Override
760                 public boolean isInfo() {
761                         return delegate.isInfo();
762                 }
763         }
764
765         public void duplicateMethodInType(AbstractMethodDeclaration methodDecl, boolean equalParameters, int severity) {
766                 if (new String(methodDecl.selector).startsWith("ajc$interMethod")) {
767                         // this is an ITD clash and will be reported in another way by AspectJ (173602)
768                         return;
769                 }
770                 super.duplicateMethodInType(methodDecl, equalParameters, severity);
771         }
772
773         // pr246393 - if we are going to complain about privileged, we clearly don't know what is going on, so don't
774         // confuse the user
775         public void parseErrorInsertAfterToken(int start, int end, int currentKind, char[] errorTokenSource, String errorTokenName,
776                         String expectedToken) {
777                 if (expectedToken.equals("privileged") || expectedToken.equals("around")) {
778                         super.parseErrorNoSuggestion(start, end, currentKind, errorTokenSource, errorTokenName);
779                 } else {
780                         super.parseErrorInsertAfterToken(start, end, currentKind, errorTokenSource, errorTokenName, expectedToken);
781                 }
782         }
783
784         public void missingValueForAnnotationMember(Annotation annotation, char[] memberName) {
785                 if (referenceContext instanceof DeclareAnnotationDeclaration) {
786                         // If a remover then the values are not necessary
787                         if (((DeclareAnnotationDeclaration) referenceContext).isRemover()) {
788                                 return;
789                         }
790                 }
791                 super.missingValueForAnnotationMember(annotation, memberName);
792         }
793
794 }