|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
* copyright (C) 2006-2007 *
|
|
|
|
* Umbrello UML Modeller Authors <uml-devel@uml.sf.net> *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
// own header
|
|
|
|
#include "javaimport.h"
|
|
|
|
|
|
|
|
// qt/kde includes
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqtextstream.h>
|
|
|
|
#include <tqstringlist.h>
|
|
|
|
#include <tqregexp.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
// app includes
|
|
|
|
#include "import_utils.h"
|
|
|
|
#include "../uml.h"
|
|
|
|
#include "../umldoc.h"
|
|
|
|
#include "../umlpackagelist.h"
|
|
|
|
#include "../package.h"
|
|
|
|
#include "../classifier.h"
|
|
|
|
#include "../enum.h"
|
|
|
|
#include "../operation.h"
|
|
|
|
#include "../attribute.h"
|
|
|
|
|
|
|
|
TQStringList JavaImport::s_filesAlreadyParsed;
|
|
|
|
int JavaImport::s_parseDepth = 0;
|
|
|
|
|
|
|
|
JavaImport::JavaImport() : NativeImportBase("//") {
|
|
|
|
setMultiLineComment("/*", "*/");
|
|
|
|
initVars();
|
|
|
|
}
|
|
|
|
|
|
|
|
JavaImport::~JavaImport() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void JavaImport::initVars() {
|
|
|
|
m_isStatic = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Catenate possible template arguments/array dimensions to the end of the type name.
|
|
|
|
TQString JavaImport::joinTypename(TQString typeName) {
|
|
|
|
if (m_source[m_srcIndex + 1] == "<" ||
|
|
|
|
m_source[m_srcIndex + 1] == "[") {
|
|
|
|
uint start = ++m_srcIndex;
|
|
|
|
if (! skipToClosing(m_source[start][0]))
|
|
|
|
return typeName;
|
|
|
|
for (uint i = start; i <= m_srcIndex; i++) {
|
|
|
|
typeName += m_source[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// to handle multidimensional arrays, call recursively
|
|
|
|
if (m_source[m_srcIndex + 1] == "[") {
|
|
|
|
typeName = joinTypename( typeName );
|
|
|
|
}
|
|
|
|
return typeName;
|
|
|
|
}
|
|
|
|
|
|
|
|
void JavaImport::fillSource(const TQString& word) {
|
|
|
|
TQString lexeme;
|
|
|
|
const uint len = word.length();
|
|
|
|
for (uint i = 0; i < len; i++) {
|
|
|
|
const TQChar& c = word[i];
|
|
|
|
if (c.isLetterOrNumber() || c == '_' || c == '.') {
|
|
|
|
lexeme += c;
|
|
|
|
} else {
|
|
|
|
if (!lexeme.isEmpty()) {
|
|
|
|
m_source.append(lexeme);
|
|
|
|
lexeme = TQString();
|
|
|
|
}
|
|
|
|
m_source.append(TQString(c));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!lexeme.isEmpty())
|
|
|
|
m_source.append(lexeme);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///Spawn off an import of the specified file
|
|
|
|
void JavaImport::spawnImport( TQString file ) {
|
|
|
|
// if the file is being parsed, don't bother
|
|
|
|
//
|
|
|
|
if (s_filesAlreadyParsed.contains( file ) ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (TQFile::exists(file)) {
|
|
|
|
JavaImport importer;
|
|
|
|
TQStringList fileList;
|
|
|
|
fileList.append( file );
|
|
|
|
s_filesAlreadyParsed.append( file );
|
|
|
|
importer.importFiles( fileList );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///returns the UML Object if found, or null otherwise
|
|
|
|
UMLObject* findObject( TQString name, UMLPackage *parentPkg ) {
|
|
|
|
UMLDoc *umldoc = UMLApp::app()->getDocument();
|
|
|
|
UMLObject * o = umldoc->findUMLObject(name, Uml::ot_UMLObject , parentPkg);
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///Resolve the specified className
|
|
|
|
UMLObject* JavaImport::resolveClass (TQString className) {
|
|
|
|
kDebug() << "importJava trying to resolve " << className << endl;
|
|
|
|
// keep track if we are dealing with an array
|
|
|
|
//
|
|
|
|
bool isArray = className.contains('[');
|
|
|
|
// remove any [] so that the class itself can be resolved
|
|
|
|
//
|
|
|
|
TQString baseClassName = className;
|
|
|
|
baseClassName.remove('[');
|
|
|
|
baseClassName.remove(']');
|
|
|
|
|
|
|
|
// java has a few implicit imports. Most relevant for this is the
|
|
|
|
// current package, which is in the same directory as the current file
|
|
|
|
// being parsed
|
|
|
|
//
|
|
|
|
TQStringList file = TQStringList::split( '/', m_currentFileName);
|
|
|
|
// remove the filename. This leaves the full path to the containing
|
|
|
|
// dir which should also include the package hierarchy
|
|
|
|
//
|
|
|
|
file.pop_back();
|
|
|
|
|
|
|
|
// the file we're looking for might be in the same directory as the
|
|
|
|
// current class
|
|
|
|
//
|
|
|
|
TQString myDir = file.join( "/" );
|
|
|
|
TQString myFile = '/' + myDir + '/' + baseClassName + ".java";
|
|
|
|
if ( TQFile::exists(myFile) ) {
|
|
|
|
spawnImport( myFile );
|
|
|
|
if ( isArray ) {
|
|
|
|
// we have imported the type. For arrays we want to return
|
|
|
|
// the array type
|
|
|
|
return Import_Utils::createUMLObject(Uml::ot_Class, className, m_scope[m_scopeIndex]);
|
|
|
|
}
|
|
|
|
return findObject(baseClassName, m_scope[m_scopeIndex]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// the class we want is not in the same package as the one being imported.
|
|
|
|
// use the imports to find the one we want.
|
|
|
|
//
|
|
|
|
TQStringList package = TQStringList::split( '.', m_currentPackage);
|
|
|
|
int dirsInPackageCount = package.size();
|
|
|
|
|
|
|
|
for (int count=0; count < dirsInPackageCount; count ++ ) {
|
|
|
|
// pop off one by one the directories, until only the source root remains
|
|
|
|
//
|
|
|
|
file.pop_back();
|
|
|
|
}
|
|
|
|
// this is now the root of any further source imports
|
|
|
|
TQString sourceRoot = '/' + file.join("/") + '/';
|
|
|
|
|
|
|
|
for (TQStringList::Iterator pathIt = m_imports.begin();
|
|
|
|
pathIt != m_imports.end(); ++pathIt) {
|
|
|
|
TQString import = (*pathIt);
|
|
|
|
TQStringList split = TQStringList::split( '.', import );
|
|
|
|
split.pop_back(); // remove the * or the classname
|
|
|
|
if ( import.endsWith( "*" ) || import.endsWith( baseClassName) ) {
|
|
|
|
// check if the file we want is in this imported package
|
|
|
|
// convert the org.test type package into a filename
|
|
|
|
//
|
|
|
|
TQString aFile = sourceRoot + split.join("/") + '/' + baseClassName + ".java";
|
|
|
|
if ( TQFile::exists(aFile) ) {
|
|
|
|
spawnImport( aFile );
|
|
|
|
// we need to set the package for the class that will be resolved
|
|
|
|
// start at the root package
|
|
|
|
UMLPackage *parent = m_scope[0];
|
|
|
|
UMLPackage *current = NULL;
|
|
|
|
|
|
|
|
for (TQStringList::Iterator it = split.begin(); it != split.end(); ++it) {
|
|
|
|
TQString name = (*it);
|
|
|
|
UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Package,
|
|
|
|
name, parent);
|
|
|
|
current = static_cast<UMLPackage*>(ns);
|
|
|
|
parent = current;
|
|
|
|
} // for
|
|
|
|
if ( isArray ) {
|
|
|
|
// we have imported the type. For arrays we want to return
|
|
|
|
// the array type
|
|
|
|
return Import_Utils::createUMLObject(Uml::ot_Class, className, current);
|
|
|
|
}
|
|
|
|
// now that we have the right package, the class should be findable
|
|
|
|
return findObject(baseClassName, current);
|
|
|
|
} // if file exists
|
|
|
|
} // if import matches
|
|
|
|
} //foreach import
|
|
|
|
return NULL; // no match
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// keep track of the current file being parsed and reset the list of imports
|
|
|
|
void JavaImport::parseFile(const TQString& filename) {
|
|
|
|
m_currentFileName= filename;
|
|
|
|
m_imports.clear();
|
|
|
|
// default visibility is Impl, unless we are an interface, then it is
|
|
|
|
// public for member vars and methods
|
|
|
|
m_defaultCurrentAccess = Uml::Visibility::Implementation;
|
|
|
|
m_currentAccess = m_defaultCurrentAccess;
|
|
|
|
s_parseDepth++;
|
|
|
|
// in the case of self referencing types, we can avoid parsing the
|
|
|
|
// file twice by adding it to the list
|
|
|
|
s_filesAlreadyParsed.append(filename);
|
|
|
|
NativeImportBase::parseFile(filename);
|
|
|
|
s_parseDepth--;
|
|
|
|
if ( s_parseDepth <= 0 ) {
|
|
|
|
// if the user decides to clear things out and reparse, we need
|
|
|
|
// to honor the request, so reset things for next time.
|
|
|
|
s_filesAlreadyParsed.clear();
|
|
|
|
s_parseDepth = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool JavaImport::parseStmt() {
|
|
|
|
const uint srcLength = m_source.count();
|
|
|
|
const TQString& keyword = m_source[m_srcIndex];
|
|
|
|
//kDebug() << '"' << keyword << '"' << endl;
|
|
|
|
if (keyword == "package") {
|
|
|
|
m_currentPackage = advance();
|
|
|
|
const TQString& qualifiedName = m_currentPackage;
|
|
|
|
TQStringList names = TQStringList::split(".", qualifiedName);
|
|
|
|
for (TQStringList::Iterator it = names.begin(); it != names.end(); ++it) {
|
|
|
|
TQString name = (*it);
|
|
|
|
UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Package,
|
|
|
|
name, m_scope[m_scopeIndex], m_comment);
|
|
|
|
m_scope[++m_scopeIndex] = static_cast<UMLPackage*>(ns);
|
|
|
|
}
|
|
|
|
if (advance() != ";") {
|
|
|
|
kError() << "importJava: unexpected: " << m_source[m_srcIndex] << endl;
|
|
|
|
skipStmt();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (keyword == "class" || keyword == "interface") {
|
|
|
|
const TQString& name = advance();
|
|
|
|
const Uml::Object_Type t = (keyword == "class" ? Uml::ot_Class : Uml::ot_Interface);
|
|
|
|
UMLObject *ns = Import_Utils::createUMLObject(t, name, m_scope[m_scopeIndex], m_comment);
|
|
|
|
m_scope[++m_scopeIndex] = m_klass = static_cast<UMLClassifier*>(ns);
|
|
|
|
m_klass->setAbstract(m_isAbstract);
|
|
|
|
m_klass->setStatic(m_isStatic);
|
|
|
|
m_klass->setVisibility(m_currentAccess);
|
|
|
|
// The UMLObject found by createUMLObject might originally have been created as a
|
|
|
|
// placeholder with a type of class but if is really an interface, then we need to
|
|
|
|
// change it.
|
|
|
|
Uml::Object_Type ot = (keyword == "interface" ? Uml::ot_Interface : Uml::ot_Class);
|
|
|
|
m_klass->setBaseType(ot);
|
|
|
|
m_isAbstract = m_isStatic = false;
|
|
|
|
// if no modifier is specified in an interface, then it means public
|
|
|
|
if ( m_klass->isInterface() ) {
|
|
|
|
m_defaultCurrentAccess = Uml::Visibility::Public;
|
|
|
|
}
|
|
|
|
if (advance() == ";") // forward declaration
|
|
|
|
return true;
|
|
|
|
if (m_source[m_srcIndex] == "<") {
|
|
|
|
// template args - preliminary, rudimentary implementation
|
|
|
|
// @todo implement all template arg syntax
|
|
|
|
uint start = m_srcIndex;
|
|
|
|
if (! skipToClosing('<')) {
|
|
|
|
kError() << "importJava(" << name << "): template syntax error" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
while (1) {
|
|
|
|
const TQString arg = m_source[++start];
|
|
|
|
if (! arg.contains( TQRegExp("^[A-Za-z_]") )) {
|
|
|
|
kDebug() << "importJava(" << name << "): cannot handle template syntax ("
|
|
|
|
<< arg << ")" << endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* UMLTemplate *tmpl = */ m_klass->addTemplate(arg);
|
|
|
|
const TQString next = m_source[++start];
|
|
|
|
if (next == ">")
|
|
|
|
break;
|
|
|
|
if (next != ",") {
|
|
|
|
kDebug() << "importJava(" << name << "): can't handle template syntax ("
|
|
|
|
<< next << ")" << endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
advance(); // skip over ">"
|
|
|
|
}
|
|
|
|
if (m_source[m_srcIndex] == "extends") {
|
|
|
|
const TQString& baseName = advance();
|
|
|
|
// try to resolve the class we are extending, or if impossible
|
|
|
|
// create a placeholder
|
|
|
|
UMLObject *parent = resolveClass( baseName );
|
|
|
|
if ( parent ) {
|
|
|
|
Import_Utils::createGeneralization(m_klass, static_cast<UMLClassifier*>(parent));
|
|
|
|
} else {
|
|
|
|
kDebug() << "importJava parentClass " << baseName
|
|
|
|
<< " is not resolveable. Creating placeholder" << endl;
|
|
|
|
Import_Utils::createGeneralization(m_klass, baseName);
|
|
|
|
}
|
|
|
|
advance();
|
|
|
|
}
|
|
|
|
if (m_source[m_srcIndex] == "implements") {
|
|
|
|
while (m_srcIndex < srcLength - 1 && advance() != "{") {
|
|
|
|
const TQString& baseName = m_source[m_srcIndex];
|
|
|
|
// try to resolve the interface we are implementing, if this fails
|
|
|
|
// create a placeholder
|
|
|
|
UMLObject *interface = resolveClass( baseName );
|
|
|
|
if ( interface ) {
|
|
|
|
Import_Utils::createGeneralization(m_klass, static_cast<UMLClassifier*>(interface));
|
|
|
|
} else {
|
|
|
|
kDebug() << "importJava implementing interface "<< baseName
|
|
|
|
<<" is not resolvable. Creating placeholder" <<endl;
|
|
|
|
Import_Utils::createGeneralization(m_klass, baseName);
|
|
|
|
}
|
|
|
|
if (advance() != ",")
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m_source[m_srcIndex] != "{") {
|
|
|
|
kError() << "importJava: ignoring excess chars at " << name
|
|
|
|
<< " (" << m_source[m_srcIndex] << ")" << endl;
|
|
|
|
skipStmt("{");
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (keyword == "enum") {
|
|
|
|
const TQString& name = advance();
|
|
|
|
UMLObject *ns = Import_Utils::createUMLObject(Uml::ot_Enum,
|
|
|
|
name, m_scope[m_scopeIndex], m_comment);
|
|
|
|
UMLEnum *enumType = static_cast<UMLEnum*>(ns);
|
|
|
|
skipStmt("{");
|
|
|
|
while (m_srcIndex < srcLength - 1 && advance() != "}") {
|
|
|
|
Import_Utils::addEnumLiteral(enumType, m_source[m_srcIndex]);
|
|
|
|
TQString next = advance();
|
|
|
|
if (next == "{" || next == "(") {
|
|
|
|
if (! skipToClosing(next[0]))
|
|
|
|
return false;
|
|
|
|
next = advance();
|
|
|
|
}
|
|
|
|
if (next != ",") {
|
|
|
|
if (next == ";") {
|
|
|
|
// @todo handle methods in enum
|
|
|
|
// For now, we cheat (skip them)
|
|
|
|
m_source[m_srcIndex] = "{";
|
|
|
|
if (! skipToClosing('{'))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (keyword == "static") {
|
|
|
|
m_isStatic = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// if we detected static previously and keyword is { then this is a static block
|
|
|
|
if (m_isStatic && keyword == "{") {
|
|
|
|
// reset static flag and jump to end of static block
|
|
|
|
m_isStatic = false;
|
|
|
|
return skipToClosing('{');
|
|
|
|
}
|
|
|
|
if (keyword == "abstract") {
|
|
|
|
m_isAbstract = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (keyword == "public") {
|
|
|
|
m_currentAccess = Uml::Visibility::Public;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (keyword == "protected") {
|
|
|
|
m_currentAccess = Uml::Visibility::Protected;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (keyword == "private") {
|
|
|
|
m_currentAccess = Uml::Visibility::Private;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (keyword == "final" ||
|
|
|
|
keyword == "native" ||
|
|
|
|
keyword == "synchronized" ||
|
|
|
|
keyword == "transient" ||
|
|
|
|
keyword == "volatile") {
|
|
|
|
//@todo anything to do here?
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (keyword == "import") {
|
|
|
|
// keep track of imports so we can resolve classes we are dependent on
|
|
|
|
TQString import = advance();
|
|
|
|
if ( import.endsWith(".") ) {
|
|
|
|
//this most likely an import that ends with a *
|
|
|
|
//
|
|
|
|
import = import + advance();
|
|
|
|
}
|
|
|
|
m_imports.append( import );
|
|
|
|
|
|
|
|
// move past ;
|
|
|
|
skipStmt();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (keyword == "@") { // annotation
|
|
|
|
advance();
|
|
|
|
if (m_source[m_srcIndex + 1] == "(") {
|
|
|
|
advance();
|
|
|
|
skipToClosing('(');
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (keyword == "}") {
|
|
|
|
if (m_scopeIndex)
|
|
|
|
m_klass = dynamic_cast<UMLClassifier*>(m_scope[--m_scopeIndex]);
|
|
|
|
else
|
|
|
|
kError() << "importJava: too many }" << endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// At this point, we expect `keyword' to be a type name
|
|
|
|
// (of a member of class or interface, or return type
|
|
|
|
// of an operation.) Up next is the name of the attribute
|
|
|
|
// or operation.
|
|
|
|
if (! keyword.contains( TQRegExp("^\\w") )) {
|
|
|
|
kError() << "importJava: ignoring " << keyword << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
TQString typeName = m_source[m_srcIndex];
|
|
|
|
typeName = joinTypename(typeName);
|
|
|
|
// At this point we need a class.
|
|
|
|
if (m_klass == NULL) {
|
|
|
|
kError() << "importJava: no class set for " << typeName << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
TQString name = advance();
|
|
|
|
TQString nextToken;
|
|
|
|
if (typeName == m_klass->getName() && name == "(") {
|
|
|
|
// Constructor.
|
|
|
|
nextToken = name;
|
|
|
|
name = typeName;
|
|
|
|
typeName = TQString();
|
|
|
|
} else {
|
|
|
|
nextToken = advance();
|
|
|
|
}
|
|
|
|
if (name.contains( TQRegExp("\\W") )) {
|
|
|
|
kError() << "importJava: expecting name in " << name << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (nextToken == "(") {
|
|
|
|
// operation
|
|
|
|
UMLOperation *op = Import_Utils::makeOperation(m_klass, name);
|
|
|
|
m_srcIndex++;
|
|
|
|
while (m_srcIndex < srcLength && m_source[m_srcIndex] != ")") {
|
|
|
|
TQString typeName = m_source[m_srcIndex];
|
|
|
|
if ( typeName == "final" || typeName.startsWith( "//") ) {
|
|
|
|
// ignore the "final" keyword and any comments in method args
|
|
|
|
typeName = advance();
|
|
|
|
}
|
|
|
|
typeName = joinTypename(typeName);
|
|
|
|
TQString parName = advance();
|
|
|
|
// the Class might not be resolved yet so resolve it if necessary
|
|
|
|
UMLObject *obj = resolveClass(typeName);
|
|
|
|
if (obj) {
|
|
|
|
// by prepending the package, unwanted placeholder types will not get created
|
|
|
|
typeName = obj->getFullyQualifiedName(".");
|
|
|
|
}
|
|
|
|
/* UMLAttribute *att = */ Import_Utils::addMethodParameter(op, typeName, parName);
|
|
|
|
if (advance() != ",")
|
|
|
|
break;
|
|
|
|
m_srcIndex++;
|
|
|
|
}
|
|
|
|
// before adding the method, try resolving the return type
|
|
|
|
UMLObject *obj = resolveClass(typeName);
|
|
|
|
if (obj) {
|
|
|
|
// using the fully qualified name means that a placeholder type will not be created.
|
|
|
|
typeName = obj->getFullyQualifiedName(".");
|
|
|
|
}
|
|
|
|
Import_Utils::insertMethod(m_klass, op, m_currentAccess, typeName,
|
|
|
|
m_isStatic, m_isAbstract, false /*isFriend*/,
|
|
|
|
false /*isConstructor*/, m_comment);
|
|
|
|
m_isAbstract = m_isStatic = false;
|
|
|
|
// reset the default visibility
|
|
|
|
m_currentAccess = m_defaultCurrentAccess;
|
|
|
|
// At this point we do not know whether the method has a body or not.
|
|
|
|
do {
|
|
|
|
nextToken = advance();
|
|
|
|
} while (nextToken != "{" && nextToken != ";");
|
|
|
|
if (nextToken == ";") {
|
|
|
|
// No body (interface or abstract)
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return skipToClosing('{');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// At this point we know it's some kind of attribute declaration.
|
|
|
|
while (1) {
|
|
|
|
while (nextToken != "," && nextToken != ";") {
|
|
|
|
if (nextToken == "=") {
|
|
|
|
if ((nextToken = advance()) == "new") {
|
|
|
|
advance();
|
|
|
|
if ((nextToken = advance()) == "(") {
|
|
|
|
skipToClosing('(');
|
|
|
|
if ((nextToken = advance()) == "{") {
|
|
|
|
skipToClosing('{');
|
|
|
|
} else {
|
|
|
|
skipStmt();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
skipStmt();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
skipStmt();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
name += nextToken; // add possible array dimensions to `name'
|
|
|
|
}
|
|
|
|
nextToken = advance();
|
|
|
|
}
|
|
|
|
// try to resolve the class type, or create a placeholder if that fails
|
|
|
|
UMLObject *type = resolveClass( typeName );
|
|
|
|
UMLObject *o;
|
|
|
|
if (type) {
|
|
|
|
o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name,
|
|
|
|
static_cast<UMLClassifier*>(type), m_comment, m_isStatic);
|
|
|
|
} else {
|
|
|
|
o = Import_Utils::insertAttribute(m_klass, m_currentAccess, name,
|
|
|
|
typeName, m_comment, m_isStatic);
|
|
|
|
}
|
|
|
|
// UMLAttribute *attr = static_cast<UMLAttribute*>(o);
|
|
|
|
if (nextToken != ",") {
|
|
|
|
// reset the modifiers
|
|
|
|
m_isStatic = m_isAbstract = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
name = advance();
|
|
|
|
nextToken = advance();
|
|
|
|
}
|
|
|
|
// reset visibility to default
|
|
|
|
m_currentAccess = m_defaultCurrentAccess;
|
|
|
|
if (m_source[m_srcIndex] != ";") {
|
|
|
|
kError() << "importJava: ignoring trailing items at " << name << endl;
|
|
|
|
skipStmt();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|