| 1 | /******************************************************************************* | 
| 2 |  * Copyright (c) 2008 IBM Corporation and others. | 
| 3 |  * All rights reserved. This program and the accompanying materials | 
| 4 |  * are made available under the terms of the Eclipse Public License v1.0 | 
| 5 |  * which accompanies this distribution, and is available at | 
| 6 |  * http://www.eclipse.org/legal/epl-v10.html | 
| 7 |  * | 
| 8 |  * Contributors: | 
| 9 |  *     IBM Corporation - initial API and implementation | 
| 10 |  *******************************************************************************/ | 
| 11 | package org.eclipse.pde.api.tools.internal.builder; | 
| 12 |   | 
| 13 | import java.util.Iterator; | 
| 14 | import java.util.List; | 
| 15 |   | 
| 16 | import org.eclipse.jdt.core.dom.ASTNode; | 
| 17 | import org.eclipse.jdt.core.dom.ASTVisitor; | 
| 18 | import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; | 
| 19 | import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; | 
| 20 | import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; | 
| 21 | import org.eclipse.jdt.core.dom.BodyDeclaration; | 
| 22 | import org.eclipse.jdt.core.dom.CompilationUnit; | 
| 23 | import org.eclipse.jdt.core.dom.EnumConstantDeclaration; | 
| 24 | import org.eclipse.jdt.core.dom.EnumDeclaration; | 
| 25 | import org.eclipse.jdt.core.dom.FieldDeclaration; | 
| 26 | import org.eclipse.jdt.core.dom.Initializer; | 
| 27 | import org.eclipse.jdt.core.dom.Javadoc; | 
| 28 | import org.eclipse.jdt.core.dom.MethodDeclaration; | 
| 29 | import org.eclipse.jdt.core.dom.TagElement; | 
| 30 | import org.eclipse.jdt.core.dom.TextElement; | 
| 31 | import org.eclipse.jdt.core.dom.TypeDeclaration; | 
| 32 | import org.eclipse.jdt.core.dom.VariableDeclarationFragment; | 
| 33 | import org.eclipse.pde.api.tools.internal.util.Util; | 
| 34 |   | 
| 35 | /** | 
| 36 |  * An AST visitor used to find missing or incorrect @since tags | 
| 37 |  *  | 
| 38 |  * @since 1.0.0 | 
| 39 |  */ | 
| 40 | public class SinceTagChecker extends ASTVisitor { | 
| 41 |          | 
| 42 |         private static final int ABORT = 0x01; | 
| 43 |         private static final int MISSING = 0x02; | 
| 44 |         private static final int HAS_JAVA_DOC = 0x04; | 
| 45 |         private static final int HAS_NO_COMMENT  = 0x10; | 
| 46 |   | 
| 47 |         private int nameStart; | 
| 48 |         int bits; | 
| 49 |         private String sinceVersion; | 
| 50 |   | 
| 51 |         /** | 
| 52 |          * Constructor | 
| 53 |          * @param nameStart | 
| 54 |          */ | 
| 55 |         public SinceTagChecker(int nameStart) { | 
| 56 |                 this.nameStart = nameStart; | 
| 57 |         } | 
| 58 |   | 
| 59 |         /* (non-Javadoc) | 
| 60 |          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CompilationUnit) | 
| 61 |          */ | 
| 62 |         public boolean visit(CompilationUnit compilationUnit) { | 
| 63 |                 return true; | 
| 64 |         } | 
| 65 |   | 
| 66 |         /* (non-Javadoc) | 
| 67 |          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.VariableDeclarationFragment) | 
| 68 |          */ | 
| 69 |         public boolean visit(VariableDeclarationFragment node) { | 
| 70 |                 if ((this.bits & ABORT) != 0) return false; | 
| 71 |                 if (node.getName().getStartPosition() == this.nameStart) { | 
| 72 |                         this.bits |= ABORT; | 
| 73 |                         ASTNode parent = node.getParent(); | 
| 74 |                         if (parent.getNodeType() == ASTNode.FIELD_DECLARATION) { | 
| 75 |                                 FieldDeclaration fieldDeclaration = (FieldDeclaration) parent; | 
| 76 |                                 processJavadoc(fieldDeclaration); | 
| 77 |                         } | 
| 78 |                 } | 
| 79 |                 return false; | 
| 80 |         } | 
| 81 |   | 
| 82 |         /* (non-Javadoc) | 
| 83 |          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnumDeclaration) | 
| 84 |          */ | 
| 85 |         public boolean visit(EnumDeclaration node) { | 
| 86 |                 return visitAbstractTypeDeclaration(node); | 
| 87 |         } | 
| 88 |   | 
| 89 |         /* (non-Javadoc) | 
| 90 |          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeDeclaration) | 
| 91 |          */ | 
| 92 |         public boolean visit(TypeDeclaration node) { | 
| 93 |                 return visitAbstractTypeDeclaration(node); | 
| 94 |         } | 
| 95 |   | 
| 96 |         /** | 
| 97 |          * @param declaration | 
| 98 |          * @return | 
| 99 |          */ | 
| 100 |         private boolean visitAbstractTypeDeclaration(AbstractTypeDeclaration declaration) { | 
| 101 |                 if ((this.bits & ABORT) != 0) { | 
| 102 |                         return false; | 
| 103 |                 } | 
| 104 |                 if (declaration.getName().getStartPosition() == this.nameStart) { | 
| 105 |                         this.bits |= ABORT; | 
| 106 |                         processJavadoc(declaration); | 
| 107 |                 } | 
| 108 |                 return true; | 
| 109 |         } | 
| 110 |   | 
| 111 |         /* (non-Javadoc) | 
| 112 |          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnnotationTypeDeclaration) | 
| 113 |          */ | 
| 114 |         public boolean visit(AnnotationTypeDeclaration node) { | 
| 115 |                 return visitAbstractTypeDeclaration(node); | 
| 116 |         } | 
| 117 |   | 
| 118 |         /* (non-Javadoc) | 
| 119 |          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration) | 
| 120 |          */ | 
| 121 |         public boolean visit(MethodDeclaration node) { | 
| 122 |                 if ((this.bits & ABORT) != 0) { | 
| 123 |                         return false; | 
| 124 |                 } | 
| 125 |                 if (node.getName().getStartPosition() == this.nameStart) { | 
| 126 |                         this.bits |= ABORT; | 
| 127 |                         processJavadoc(node); | 
| 128 |                 } | 
| 129 |                 return false; | 
| 130 |         } | 
| 131 |   | 
| 132 |         /* (non-Javadoc) | 
| 133 |          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration) | 
| 134 |          */ | 
| 135 |         public boolean visit(AnnotationTypeMemberDeclaration node) { | 
| 136 |                 if ((this.bits & ABORT) != 0) { | 
| 137 |                         return false; | 
| 138 |                 } | 
| 139 |                 if (node.getName().getStartPosition() == this.nameStart) { | 
| 140 |                         this.bits |= ABORT; | 
| 141 |                         processJavadoc(node); | 
| 142 |                 } | 
| 143 |                 return false; | 
| 144 |         } | 
| 145 |          | 
| 146 |         /* (non-Javadoc) | 
| 147 |          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Initializer) | 
| 148 |          */ | 
| 149 |         public boolean visit(Initializer node) { | 
| 150 |                 return false; | 
| 151 |         } | 
| 152 |          | 
| 153 |         /* (non-Javadoc) | 
| 154 |          * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnumConstantDeclaration) | 
| 155 |          */ | 
| 156 |         public boolean visit(EnumConstantDeclaration node) { | 
| 157 |                 if ((this.bits & ABORT) != 0) { | 
| 158 |                         return false; | 
| 159 |                 } | 
| 160 |                 if (node.getName().getStartPosition() == this.nameStart) { | 
| 161 |                         this.bits |= ABORT; | 
| 162 |                         processJavadoc(node); | 
| 163 |                 } | 
| 164 |                 return false; | 
| 165 |         } | 
| 166 |          | 
| 167 |         /** | 
| 168 |          * Processes a javadoc tag | 
| 169 |          * @param bodyDeclaration | 
| 170 |          */ | 
| 171 |         private void processJavadoc(BodyDeclaration bodyDeclaration) { | 
| 172 |                 Javadoc javadoc = bodyDeclaration.getJavadoc(); | 
| 173 |                 boolean found = false; | 
| 174 |                 if (javadoc != null) { | 
| 175 |                         this.bits |= HAS_JAVA_DOC; | 
| 176 |                         List tags = javadoc.tags(); | 
| 177 |                         for (Iterator iterator = tags.iterator(); iterator.hasNext();) { | 
| 178 |                                 TagElement element = (TagElement) iterator.next(); | 
| 179 |                                 String tagName = element.getTagName(); | 
| 180 |                                 if (TagElement.TAG_SINCE.equals(tagName)) { | 
| 181 |                                         // @since is present | 
| 182 |                                         // check if valid | 
| 183 |                                         found = true; | 
| 184 |                                         List fragments = element.fragments(); | 
| 185 |                                         if (fragments.size() >= 1) { | 
| 186 |                                                 ASTNode fragment = (ASTNode) fragments.get(0); | 
| 187 |                                                 if (fragment.getNodeType() == ASTNode.TEXT_ELEMENT) { | 
| 188 |                                                         this.sinceVersion = ((TextElement) fragment).getText(); | 
| 189 |                                                 } | 
| 190 |                                         } else { | 
| 191 |                                                 this.sinceVersion = Util.EMPTY_STRING; | 
| 192 |                                         } | 
| 193 |                                         break; | 
| 194 |                                 } | 
| 195 |                         } | 
| 196 |                         if (!found) { | 
| 197 |                                 this.bits |= MISSING; | 
| 198 |                         } | 
| 199 |                 } else { | 
| 200 |                         this.bits |= HAS_NO_COMMENT; | 
| 201 |                 } | 
| 202 |         } | 
| 203 |         /** | 
| 204 |          * @return if the javadoc tag is missing | 
| 205 |          */ | 
| 206 |         public boolean isMissing() { | 
| 207 |                 return (this.bits & MISSING) != 0; | 
| 208 |         } | 
| 209 |   | 
| 210 |         /** | 
| 211 |          * @return if there is no javadoc tag | 
| 212 |          */ | 
| 213 |         public boolean hasNoComment() { | 
| 214 |                 return (this.bits & HAS_NO_COMMENT) != 0; | 
| 215 |         } | 
| 216 |   | 
| 217 |         /** | 
| 218 |          * @return if there already is a doc comment | 
| 219 |          */ | 
| 220 |         public boolean hasJavadocComment() { | 
| 221 |                 return (this.bits & HAS_JAVA_DOC) != 0; | 
| 222 |         } | 
| 223 |   | 
| 224 |         /** | 
| 225 |          * @return the version the should be placed in the tag | 
| 226 |          */ | 
| 227 |         public String getSinceVersion() { | 
| 228 |                 if (this.sinceVersion != null) | 
| 229 |                         return this.sinceVersion.trim(); | 
| 230 |                 return null; | 
| 231 |         } | 
| 232 | } |