View Javadoc

    1   /*
    2    * Copyright (c) 2001-2003 The XDoclet team
    3    * All rights reserved.
    4    */
    5   package xjavadoc;
    6
    7   import xjavadoc.filesystem.AbstractFile;
    8   import xjavadoc.filesystem.XJavadocFile;
    9   import xjavadoc.filesystem.ReaderFile;
    10
    11  import java.util.*;
    12  import java.io.*;
    13
    14  /***
    15   * This class represents a class for which the source code is available
    16   *XJavaDocFil
    17   * @author    Aslak Hellesøy
    18   * @created   3. januar 2002
    19   */
    20  public final class SourceClass extends AbstractClass
    21  {
    22  	public static int  instanceCount = 0;
    23
    24  	private final Map  _qualifiedClasses = new HashMap();
    25
    26  	private final boolean _isExtraClass;
    27
    28  	private final List _tagsForValidation = new ArrayList();
    29
    30  	/***
    31  	 * The root node of the AST
    32  	 */
    33  	private SimpleNode _compilationUnit;
    34
    35  	private Reader     _in = null;
    36
    37  	/***
    38  	 * Keep a ref to the file in case of warning reporting
    39  	 */
    40  	private AbstractFile _sourceFile;
    41
    42  	//private JavaParser _parser;
    43
    44  	/***
    45  	 * doe we nees saving?
    46  	 */
    47  	private boolean    _dirty;
    48
    49  	/***
    50  	 * Constructor to use for inner classes.
    51  	 *
    52  	 * @param containingClass  The containing class;
    53  	 */
    54  	public SourceClass( SourceClass containingClass, XTagFactory tagFactory )
    55  	{
    56  		super( containingClass, tagFactory );
    57  		setContainingPackage( containingClass.getContainingPackage().getName() );
    58  		_isExtraClass = false;
    59  	}
    60
    61  	/***
    62  	 * Constructor to use for "extra" classes, that is, secondary classes that
    63  	 * figure in the same source.
    64  	 *
    65  	 * @param mainClass  The containing class. Or rather the "main" class in the
    66  	 *      source.
    67  	 * @param dummy
    68  	 */
    69  	public SourceClass( SourceClass mainClass, int dummy, XTagFactory tagFactory )
    70  	{
    71  		super( mainClass.getXJavaDoc(), tagFactory );
    72  		setContainingPackage( mainClass.getContainingPackage().getName() );
    73  		_isExtraClass = true;
    74  		_sourceFile = mainClass.getFile();
    75  	}
    76
    77  	/***
    78  	 * Constructor to use for outer classes
    79  	 *
    80  	 * @param sourceFile  The file containing the source
    81  	 */
    82  	public SourceClass( XJavaDoc xJavaDoc, File sourceFile, XTagFactory tagFactory )
    83  	{
    84  		this( xJavaDoc, new XJavadocFile( sourceFile ), false, tagFactory, null );
    85  	}
    86
    87  	/***
    88  	 * Constructor to use for outer classes
    89  	 *
    90  	 * @param sourceFile  The file containing the source
    91  	 */
    92  	public SourceClass( XJavaDoc xJavaDoc, Reader sourceFile, XTagFactory tagFactory )
    93  	{
    94  		this( xJavaDoc, new ReaderFile( sourceFile ), false, tagFactory, null);
    95  	}
    96
    97  	/***
    98  	 * @param sourceFile
    99  	 * @param useNodeParser
    100 	 */
    101 	public SourceClass( XJavaDoc xJavaDoc, File sourceFile, boolean useNodeParser, XTagFactory tagFactory )
    102 	{
    103 		this( xJavaDoc, new XJavadocFile( sourceFile ), useNodeParser, tagFactory ,null );
    104 	}
    105
    106 	/***
    107 	 * Constructor to use for outer classes
    108 	 *
    109 	 * @param sourceFile     The file containing the source
    110 	 * @param useNodeParser
    111 	 */
    112 	public SourceClass( XJavaDoc xJavaDoc, AbstractFile sourceFile, boolean useNodeParser, XTagFactory tagFactory ,String encoding)
    113 	{
    114 		super( xJavaDoc, tagFactory );
    115 		if( sourceFile == null )
    116 		{
    117 			throw new IllegalArgumentException( "sourceFile can't be null for outer classes!" );
    118 		}
    119 		_sourceFile = sourceFile;
    120
    121 		try
    122 		{
    123 			_in = sourceFile.getReader(encoding);
    124 			parse( useNodeParser );
    125 		}
    126 		catch( IOException e )
    127 		{
    128 			// That's tough. Shouldn't happen
    129 			if(encoding==null)
    130 			{
    131 			throw new IllegalStateException( "Couldn't find " + sourceFile );
    132 		}
    133 			else
    134 			{
    135 				throw new IllegalStateException( "Invalid Encoding '"+encoding+"' or couldn't find '" + sourceFile +"'");
    136 			}
    137 		}
    138
    139 		instanceCount++;
    140 		_dirty = false;
    141 		_isExtraClass = false;
    142 	}
    143
    144 	/***
    145 	 * Describe what the method does
    146 	 *
    147 	 * @param qualifiedName  Describe what the parameter does
    148 	 * @return               Describe the return value
    149 	 */
    150 	public static String getFileName( String qualifiedName )
    151 	{
    152 		return qualifiedName.replace( '.', File.separatorChar ) + ".java";
    153 	}
    154
    155 	public boolean isExtraClass()
    156 	{
    157 		return _isExtraClass;
    158 	}
    159
    160 	/***
    161 	 * Returns "1", "2", etc., depending on how many inner classes we have.
    162 	 *
    163 	 * @return String containing number of next anonymous inner class
    164 	 */
    165 	public String getNextAnonymousClassName()
    166 	{
    167 		return String.valueOf( getInnerClasses().size() + 1 );
    168 	}
    169
    170 	/***
    171 	 * Gets the OuterClass attribute of the SourceClass object
    172 	 *
    173 	 * @return   The OuterClass value
    174 	 */
    175 	private boolean isOuterClass()
    176 	{
    177 		return _sourceFile != null;
    178 	}
    179
    180 	/***
    181 	 * Gets the Writeable attribute of the SourceClass object
    182 	 *
    183 	 * @return   The Writeable value
    184 	 */
    185 	public boolean isWriteable()
    186 	{
    187 		return _compilationUnit != null;
    188 	}
    189
    190 	public SimpleNode getCompilationUnit()
    191 	{
    192 		return _compilationUnit;
    193 	}
    194
    195 	/***
    196 	 * Returns a reader for the source code.
    197 	 *
    198 	 * @return   a reader for the source code.
    199 	 */
    200 	public Reader getReader()
    201 	{
    202 		return _in;
    203 	}
    204
    205 	public AbstractFile getFile()
    206 	{
    207 		return _sourceFile;
    208 	}
    209
    210 	public boolean isPrimitive()
    211 	{
    212 		return false;
    213 	}
    214
    215 	/***
    216 	 * say this class is dirty and needs saving propagate to outer class ( if any )
    217 	 */
    218 	public void setDirty()
    219 	{
    220 		if( isInner() )
    221 		{
    222 			getContainingClass().setDirty();
    223 		}
    224 		else
    225 		{
    226 			_dirty = true;
    227 		}
    228 	}
    229 	/***
    230 	 * Called by JavaParser at the end of the parsing
    231 	 *
    232 	 * @param compilationUnit  The new CompilationUnit value
    233 	 */
    234 	public void setCompilationUnit( SimpleNode compilationUnit )
    235 	{
    236 		_compilationUnit = compilationUnit;
    237 	}
    238
    239 	/***
    240 	 * Called by XJavaDoc after the entire source is parsed, but only if validation
    241 	 * is on.
    242 	 *
    243 	 * @throws TagValidationException
    244 	 */
    245 	public void validateTags() throws TagValidationException
    246 	{
    247 		// Validate the tags on the class level and on our members.
    248 		for( Iterator i = _tagsForValidation.iterator(); i.hasNext();  )
    249 		{
    250 			XTag tag = ( XTag ) i.next();
    251
    252 			tag.validate();
    253 		}
    254
    255 		// then validate tags in all our inner classes.
    256 		for( Iterator i = getInnerClasses().iterator(); i.hasNext();  )
    257 		{
    258 			SourceClass inner = ( SourceClass ) i.next();
    259
    260 			inner.validateTags();
    261 		}
    262 	}
    263
    264 	public void addTagForValidation( DefaultXTag tag )
    265 	{
    266 		_tagsForValidation.add( tag );
    267 	}
    268
    269 	public boolean saveNeeded()
    270 	{
    271 		return isWriteable() && _dirty;
    272 	}
    273
    274 	/***
    275 	 * Describe what the method does
    276 	 *
    277 	 * @return   Describe the return value
    278 	 */
    279 	public long lastModified()
    280 	{
    281 		if( isOuterClass() )
    282 		{
    283 			return _sourceFile.lastModified();
    284 		}
    285 		else
    286 		{
    287 			return getContainingClass().lastModified();
    288 		}
    289 	}
    290
    291 	/***
    292 	 * Prints this class to a stream
    293 	 *
    294 	 * @param out  Describe what the parameter does
    295 	 */
    296 	public void print( Writer out )
    297 	{
    298 		updateDoc();
    299 		if( !isWriteable() )
    300 		{
    301 			// parsed with simple parser
    302 			throw new UnsupportedOperationException( "Can't save classes that are parsed with simpleparser" );
    303 		}
    304 		NodePrinter.print( _compilationUnit, out );
    305 	}
    306
    307 	/***
    308 	 * Saves the class at root dir rootDir. The actual java file is derived from
    309 	 * tha package name. If no root dir is specified, save where it was loaded from
    310 	 *
    311 	 * @param rootDir       the root directory.
    312 	 * @return              the relative fileName to which the file was saved.
    313 	 * @throws IOException  if the file couldn't be saved
    314 	 */
    315 	public String save( File rootDir ) throws IOException
    316 	{
    317 		if( !isWriteable() )
    318 		{
    319 			throw new UnsupportedOperationException( "Can't save classes that aren't parsed in AST mode (do getXJavaDoc().setUseNodeParser(true) before parsing starts!)" );
    320 		}
    321 		if( getContainingClass() != null )
    322 		{
    323 			// inner class. can't save these.
    324 			throw new UnsupportedOperationException( "Can't save inner classes" );
    325 		}
    326 		else if( rootDir != null )
    327 		{
    328 			String fileName = getFileName( getQualifiedName() );
    329 			File javaFile = new File( rootDir, fileName );
    330
    331 			javaFile.getParentFile().mkdirs();
    332 			FileWriter fwtr = new FileWriter( javaFile );
    333 			print( fwtr );
    334 			fwtr.flush();
    335 			fwtr.close();
    336 			return fileName;
    337 		}
    338 		else
    339 		{
    340 			// no root dir specified, save in place
    341 			Writer outputStream = _sourceFile.getWriter();
    342
    343 			print( new PrintWriter( outputStream ) );
    344 			outputStream.flush();
    345 			outputStream.close();
    346 			return _sourceFile.toString();
    347 		}
    348 	}
    349
    350 	/***
    351 	 * Returns fully qualified name of a class. 1: check for "." 2: if "." it's
    352 	 * already qualified 3: if no ".", must try with all imported packages or
    353 	 * classes
    354 	 *
    355 	 * @param unqualifiedClassName  Describe what the parameter does
    356 	 * @return                      Describe the return value
    357 	 */
    358 	public XClass qualify( final String unqualifiedClassName )
    359 	{
    360 		XClass result = null;
    361
    362 		result = ( XClass ) _qualifiedClasses.get( unqualifiedClassName );
    363 		if( result == null )
    364 		{
    365
    366 			if( getContainingClass() == null )
    367 			{
    368 				// If there are dots, consider it to be qualified or a reference to an inner class in one
    369 				// of the imported classes.
    370 				if( unqualifiedClassName.indexOf( '.' ) != -1 )
    371 				{
    372 					result = unqualifiedNameInImportedClassesInnerClasses( unqualifiedClassName );
    373 					if( result == null )
    374 					{
    375 						// It wasn't a ref to an imported inner class. Consider it already qualified
    376 						result = getXJavaDoc().getXClass( unqualifiedClassName );
    377 					}
    378 				}
    379 				else
    380 				{
    381 					// There are no dots in the class name. It's a primitive or unqualified.
    382 					Primitive primitive;
    383
    384 					if( ( primitive = XJavaDoc.getPrimitive( unqualifiedClassName ) ) != null )
    385 					{
    386 						result = primitive;
    387 					}
    388 					else
    389 					{
    390 						String qualifiedName;
    391
    392 						if( ( qualifiedName = unqualifiedNameInTheSameClassAsAnInnerClass( unqualifiedClassName ) ) != null )
    393 						{
    394 							result = getXJavaDoc().getXClass( qualifiedName );
    395 						}
    396 						else if( ( qualifiedName = unqualifiedNameInInnerClasses( unqualifiedClassName ) ) != null )
    397 						{
    398 							result = getXJavaDoc().getXClass( qualifiedName );
    399 						}
    400 						else if( ( qualifiedName = unqualifiedNameInJavaDotLang( unqualifiedClassName ) ) != null )
    401 						{
    402 							result = getXJavaDoc().getXClass( qualifiedName );
    403 						}
    404 						else if( ( qualifiedName = unqualifiedNameInImportedClasses( unqualifiedClassName ) ) != null )
    405 						{
    406 							result = getXJavaDoc().getXClass( qualifiedName );
    407 						}
    408 						else if( ( qualifiedName = unqualifiedNameInImportedPackages( unqualifiedClassName ) ) != null )
    409 						{
    410 							result = getXJavaDoc().getXClass( qualifiedName );
    411 						}
    412 						else if( ( qualifiedName = unqualifiedNameInTheSamePackage( unqualifiedClassName ) ) != null )
    413 						{
    414 							result = getXJavaDoc().getXClass( qualifiedName );
    415 						}
    416                         else if( ( qualifiedName = unqualifiedNameInInnerClassesOfSuperClass( unqualifiedClassName ) ) != null )
    417                         {
    418                             result = getXJavaDoc().getXClass( qualifiedName );
    419                         }
    420                         else if( ( qualifiedName = unqualifiedNameInInnerInterface( unqualifiedClassName ) ) != null )
    421                         {
    422                             result = getXJavaDoc().getXClass( qualifiedName );
    423                         }
    424 						else
    425 						{
    426 							String unknownClassName;
    427
    428 							if( getContainingPackage().getName().equals( "" ) )
    429 							{
    430 								unknownClassName = unqualifiedClassName;
    431 							}
    432 							else
    433 							{
    434 								unknownClassName = getContainingPackage().getName() + "." + unqualifiedClassName;
    435 							}
    436
    437 							UnknownClass unknownClass = new UnknownClass( getXJavaDoc(), unknownClassName );
    438
    439 							/*
    440 							 * We couldn't qualify the class. If there are no package import statements,
    441 							 * we'll assume the class belongs to the same package as ourself.
    442 							 */
    443 							if( !hasImportedPackages() )
    444 							{
    445 								// No import foo.bar.* statements. Just add an informative message that we guessed
    446 								getXJavaDoc().logMessage( this, unknownClass, unqualifiedClassName, XJavaDoc.NO_IMPORTED_PACKAGES );
    447 							}
    448 							else
    449 							{
    450
    451 								// We can't decide. Add a warning that will be displayed in the end.
    452 								getXJavaDoc().logMessage( this, unknownClass, unqualifiedClassName, XJavaDoc.ONE_OR_MORE_IMPORTED_PACKAGES );
    453 							}
    454 							result = unknownClass;
    455 						}
    456 					}
    457 				}
    458 			}
    459 			else
    460 			{
    461 				result = getContainingAbstractClass().qualify( unqualifiedClassName );
    462 			}
    463 			_qualifiedClasses.put( unqualifiedClassName, result );
    464 		}
    465
    466 		return result;
    467 	}
    468
    469 	public void reset()
    470 	{
    471 		super.reset();
    472
    473 		_compilationUnit = null;
    474 		_in = null;
    475 		_sourceFile = null;
    476 		_qualifiedClasses.clear();
    477 	}
    478
    479 	private final String unqualifiedNameInImportedClasses( final String unqualifiedClassName )
    480 	{
    481 		if( !hasImportedClasses() )
    482 		{
    483 			return null;
    484 		}
    485
    486 		final String suffix = "." + unqualifiedClassName;
    487 		String candidate = null;
    488
    489 		for( Iterator i = getImportedClasses().iterator(); i.hasNext();  )
    490 		{
    491 			XClass clazz = ( XClass ) i.next();
    492 			String qualifiedClassName = clazz.getQualifiedName();
    493
    494 			if( qualifiedClassName.endsWith( suffix ) )
    495 			{
    496 				// perform sanity check for ambiguous imports
    497 				if( candidate != null && !candidate.equals( qualifiedClassName ) )
    498 				{
    499 					// ambiguous class import
    500 					throw new IllegalStateException( "In class " + getQualifiedName() + ": Ambiguous class:" + unqualifiedClassName + ". Is it " + candidate + " or " + qualifiedClassName + "?" );
    501 				}
    502 				else
    503 				{
    504 					candidate = qualifiedClassName;
    505 				}
    506 			}
    507 		}
    508 		return candidate;
    509 	}
    510
    511 	private final XClass unqualifiedNameInImportedClassesInnerClasses( final String unqualifiedClassName )
    512 	{
    513 		if( !hasImportedClasses() )
    514 		{
    515 			return null;
    516 		}
    517
    518 		XClass candidate = null;
    519
    520 		for( Iterator i = getImportedClasses().iterator(); i.hasNext();  )
    521 		{
    522 			XClass clazz = ( XClass ) i.next();
    523
    524 			// See if it's among the inner classes.
    525 			for( Iterator inners = clazz.getInnerClasses().iterator(); inners.hasNext();  )
    526 			{
    527 				XClass inner = ( XClass ) inners.next();
    528 				boolean isAccessible = inner.isPublic();
    529
    530 				if( inner.getName().equals( unqualifiedClassName ) && isAccessible )
    531 				{
    532 					if( candidate != null )
    533 					{
    534 						// ambiguous class import
    535 						throw new IllegalStateException( "In class " + getQualifiedName() + ": Ambiguous class:" + unqualifiedClassName + ". Is it " + candidate.getQualifiedName() + " or " + inner.getQualifiedName() + "?" );
    536 					}
    537 					else
    538 					{
    539 						candidate = inner;
    540 					}
    541 				}
    542 			}
    543 		}
    544 		return candidate;
    545 	}
    546
    547 	/***
    548 	 * Describe what the method does
    549 	 *
    550 	 * @param unqualifiedClassName  Describe what the parameter does
    551 	 * @return                      Describe the return value
    552 	 */
    553 	private final String unqualifiedNameInInnerClasses( final String unqualifiedClassName )
    554 	{
    555 		if( !hasInnerClasses() )
    556 		{
    557 			return null;
    558 		}
    559
    560 		final String innerClassName = getQualifiedName() + '.' + unqualifiedClassName;
    561
    562 		String candidate = null;
    563
    564 		for( Iterator i = getInnerClasses().iterator(); i.hasNext();  )
    565 		{
    566 			XClass innerClass = ( XClass ) i.next();
    567 			String qualifiedClassName = innerClass.getQualifiedName();
    568
    569 			if( innerClassName.equals( qualifiedClassName ) )
    570 			{
    571 				candidate = qualifiedClassName;
    572 				break;
    573 			}
    574 		}
    575 		return candidate;
    576 	}
    577
    578 	/***
    579 	 * Resolves Inner interfaces that exist in current class.
    580     *
    581     * This catches inner classes as well because isInterface()
    582     * does not indicate if it's an interface.
    583 	 *
    584 	 * @param unqualifiedClassName  Name of the class to resolve
    585 	 * @return                      The qualified name of the inner class.
    586 	 */
    587 	private final String unqualifiedNameInInnerInterface( final String unqualifiedClassName )
    588 	{
    589         String qualifiedClassName = getQualifiedName() + '$' + unqualifiedClassName;
    590         if (getXJavaDoc().classExists(qualifiedClassName)) {
    591 //            // The isInterface() method is not implemented for source classes.
    592 //            if (XJavaDoc.getInstance().getXClass(qualifiedClassName).isInterface()) {
    593 //                return getQualifiedName() + '.' + unqualifiedClassName;
    594 //            }
    595             return getQualifiedName() + '.' + unqualifiedClassName;
    596         }
    597 		return null;
    598 	}
    599
    600 	/***
    601 	 * Resolves Inner classes that exist in the super class hierarchy.
    602 	 *
    603 	 * @param unqualifiedClassName  Name of the class to resolve
    604 	 * @return                      The qualified name of the inner class.
    605 	 */
    606 	private final String unqualifiedNameInInnerClassesOfSuperClass( final String unqualifiedClassName )
    607 	{
    608         XClass clazz = getXJavaDoc().getXClass(getQualifiedName());
    609         XClass superClazz = clazz.getSuperclass();
    610         while (superClazz != null && ! superClazz.getQualifiedName().equals("java.lang.Object")) {
    611 		    String innerClassName = superClazz.getQualifiedName() + '.' + unqualifiedClassName;
    612             for( Iterator i = superClazz.getInnerClasses().iterator(); i.hasNext();  )
    613             {
    614                 XClass innerClass = ( XClass ) i.next();
    615                 String qualifiedClassName = innerClass.getQualifiedName();
    616                 if( innerClassName.equals( qualifiedClassName ) )
    617                 {
    618                     return qualifiedClassName;
    619                 }
    620             }
    621             superClazz = superClazz.getSuperclass();
    622         }
    623 		return null;
    624 	}
    625
    626 	/***
    627 	 * Describe what the method does
    628 	 *
    629 	 * @param unqualifiedClassName  Describe what the parameter does
    630 	 * @return                      Describe the return value
    631 	 */
    632 	private final String unqualifiedNameInImportedPackages( final String unqualifiedClassName )
    633 	{
    634 		if( !hasImportedPackages() )
    635 		{
    636 			return null;
    637 		}
    638
    639 		final String suffix = "." + unqualifiedClassName;
    640 		String candidate = null;
    641
    642 		for( Iterator i = getImportedPackages().iterator(); i.hasNext();  )
    643 		{
    644 			String importedPackageName = ( ( XPackage ) i.next() ).getName();
    645 			String qualifiedClassName = importedPackageName + suffix;
    646
    647 			if( getXJavaDoc().classExists( qualifiedClassName ) )
    648 			{
    649 				if( candidate != null && !candidate.equals( qualifiedClassName ) )
    650 				{
    651 					// ambiguous class import
    652 					throw new IllegalStateException( "In class " + getQualifiedName() + ": Ambiguous class:" + unqualifiedClassName + ". Is it " + candidate + " or " + qualifiedClassName + "?" );
    653 				}
    654 				else
    655 				{
    656 					candidate = qualifiedClassName;
    657 				}
    658 			}
    659 		}
    660 		return candidate;
    661 	}
    662
    663 	/***
    664 	 * Returns the fully qualified class name if it's found in java.lang, otherwise
    665 	 * null.
    666 	 *
    667 	 * @param unqualifiedClassName
    668 	 * @return fully qualified class name, or null
    669 	 */
    670 	private final String unqualifiedNameInJavaDotLang( final String unqualifiedClassName )
    671 	{
    672 		String qualifiedClassName = "java.lang." + unqualifiedClassName;
    673
    674 		if( getXJavaDoc().classExists( qualifiedClassName ) )
    675 		{
    676 			return qualifiedClassName;
    677 		}
    678 		else
    679 		{
    680 			return null;
    681 		}
    682 	}
    683
    684 	/***
    685 	 * Describe what the method does
    686 	 *
    687 	 * @param unqualifiedClassName  Describe what the parameter does
    688 	 * @return                      Describe the return value
    689 	 */
    690 	private final String unqualifiedNameInTheSamePackage( final String unqualifiedClassName )
    691 	{
    692 		String qualifiedClassName;
    693
    694 		if( getContainingPackage().getName().equals( "" ) )
    695 		{
    696 			qualifiedClassName = unqualifiedClassName;
    697 		}
    698 		else
    699 		{
    700 			qualifiedClassName = getContainingPackage().getName() + '.' + unqualifiedClassName;
    701 		}
    702
    703 		if( getXJavaDoc().classExists( qualifiedClassName ) )
    704 		{
    705 			return qualifiedClassName;
    706 		}
    707 		else
    708 		{
    709 			return null;
    710 		}
    711
    712 	}
    713
    714 	private final String unqualifiedNameInTheSameClassAsAnInnerClass( final String unqualifiedClassName )
    715 	{
    716 		//containing class=com.p.A, inner-reference=B ->com.p.A.B
    717 		String qualifiedClassName = getQualifiedName() + '.' + unqualifiedClassName;
    718
    719 		if( getXJavaDoc().classExists( qualifiedClassName ) )
    720 			return qualifiedClassName;
    721
    722 		//containing class=com.p.A, inner-reference=A.B ->com.p.A.B
    723 		if( getContainingPackage().getName().equals( "" ) )
    724 		{
    725 			qualifiedClassName = unqualifiedClassName;
    726 		}
    727 		else
    728 		{
    729 			qualifiedClassName = getContainingPackage().getName() + '.' + unqualifiedClassName;
    730 		}
    731
    732 		if( getXJavaDoc().classExists( qualifiedClassName ) )
    733 			return qualifiedClassName;
    734
    735 		return null;
    736 	}
    737
    738 	/***
    739 	 * Describe what the method does
    740 	 *
    741 	 * @param useNodeParser  Describe what the parameter does
    742 	 */
    743 	private void parse( boolean useNodeParser )
    744 	{
    745 		try
    746 		{
    747 			if( useNodeParser )
    748 			{
    749 				// We need a pool of parsers, because parsing one file
    750 				// might kick away the parsing of another etc.
    751 //				_nodeParser.populate( this );
    752 				new NodeParser( getXJavaDoc(), getTagFactory() ).populate( this );
    753 			}
    754 			else
    755 			{
    756 //				_simpleParser.populate( this );
    757 				new SimpleParser( getXJavaDoc(), getTagFactory() ).populate( this );
    758 			}
    759 		}
    760 		catch( ParseException e )
    761 		{
    762 			// Source code is bad. Not according to grammar. User's fault.
    763 			String cls = _sourceFile != null ? _sourceFile.toString() : getQualifiedName();
    764
    765 			System.err.println( "Error parsing " + cls + ':' + e.getMessage() );
    766 		}
    767 		catch( TokenMgrError e )
    768 		{
    769 			String cls = _sourceFile != null ? _sourceFile.toString() : getQualifiedName();
    770
    771 			System.err.println( "Error parsing " + cls + ':' + e.getMessage() );
    772 		}
    773 	}
    774 }