1.0 Compiler - Limitations and known problems
1.1 Incremental compilation
1.2 Problem handling
1.3 Exporting types
1.4 Debug attributes
1.5 Inner types
1.5.1 Default
abstract methods
1.5.2 Imports in
default package
1.5.3 Explicit
qualification
1.5.4
this.super()
1.5.5 Access to
synthetic names
1.5.6 Method
overloading
1.5.7 Anonymous
type modifiers
1.5.8 Visibility of
sibling classes
1.5.9 Accessing static fields from a static member type
1.6 Other clarifications and limitations
1.6.1 Circular
constructor invocation
1.6.2 Incompatible
interfaces
1.6.3 Class and
method collisions
1.6.4 Method
ordering on export
1.6.5 Type
visibility in a default package
1.6.6 Empty
statements
1.6.7 Simple
name imports
1.6.8 Protected
constructor visibility
1.6.9 Numeric
underflow
1.6.10 Definite
assignment in dead code
1.6.11 Assignment
conversion
1.6.12 Incremental
compiler may produce conflicting serialVersionUID
1.6.13 Static
final variable dependency analysis
1.6.14 Side Effects of
copy/rename
2.0 Searching
3.0 Referenced types
4.0 Project limitations
5.0 .class files in the IDE
VisualAge for Java implements the Java Language Specification. In areas where the specification is unclear, VisualAge for Java uses J2SDK(TM) v1.2.2 as a reference implementation.
VisualAge for Java supports incremental compilation. Incremental compilation allows the developer to see the effects of his/her changes as they are made, rather than explicitly invoking the compiler periodically to find the problems that have been introduced during the last edit cycle. In addition to compiling the method that the developer has just changed, any methods that are impacted by this change are also automatically recompiled. Changing (or adding or deleting) a class definition also triggers this automatic recompilation. As a result, binary compatibility is automatically ensured by the compiler for any program implemented within the environment.
These incremental changes take effect immediately. A thread that is repeatedly invoking a method immediately starts executing the new method. Code may be changed in the debugger as well; any change in the debugger takes effect upon completion and saving of the edit.
All problems that are detected are classified as either warnings or errors. Warnings are reported on problems that can be ignored by the
compiler without changing the semantics of the developer's program. The existence of a warning does not
affect the execution of the program; the code executes as if it were written correctly
(for example, detecting unreachable code does not prevent running it). Errors are
more severe problems that cannot be ignored since the semantics of the program are corrupted, and therefore its execution cannot
complete. If there is an error in a method, the debugger shows the problem description and a stack trace containing the problem method
(or if it is an initialization problem, the constructor or the code that triggered the static initialization). A method with an error
cannot be run until the error is fixed.
The VisualAge for Java compiler detects problems in several phases (for example, parsing, type checking, code generation, ...). Proceeding to the
next phase is allowed only if no error has been detected so far. Thus errors detected in some phases cause the compilation process to
be aborted. Therefore, fixing a compilation problem may reveal other previously unreported problems.
Some problems are more serious than others. If a class subclasses a nonexistent class for example, VisualAge for Java cannot create instances of
this class. It is also difficult to accurately compile methods when much of the context is unavailable. Under these conditions, the
compiler ignores the methods. Later, when the missing classes and interfaces are available, the methods are fully compiled
automatically.
The conditions above may cause reported problems to appear to have been lost:
a. The problems have been superseded by more significant errors and just discarded. If the more serious errors are resolved, these
problems will return.
b. A field initialization problem was detected and reported against the constructor. When such a constructor is saved, the
problem report is "credited" to the class and no longer kept with the constructor.
Classes must be syntactically correct in order for the compiler to accept them; however methods only need a syntactically valid method
header. Such a method is recorded in the workspace as a problem method, and behaves as described above.
Some problems reported on classes do not provide source highlighting. For these problems, you should attempt to deduce the effected type
and find it in the class definition source.
A type can be exported in two formats: .java or .class. A type in the environment that is from a .class file can only be exported in .class format since there is no source available. Any source class can be exported as either .java or .class format. The IDE does not allow a developer to export in .class format if there are any errors in the class - these errors must be corrected first. However, it is possible to export in .java format even if there are errors. In this case, the resulting file is not valid input for another java compiler.
The VisualAge for Java compiler produces debug attributes (if requested).
A Java compiler must prevent any user code from explicitly reading an uninitialized local variable, however a program may get interrupted
in a state where some variables are not yet set, but already declared (user interrupt, ...) and a debugger may try to show all visible
variables at this point using the debug attributes recorded in .class files for this purpose. These debug attributes contain the
visibility range for each local variable, and VisualAge for Java considers each variable to be visible from its declaration to the end of its
definition scope, where other compilers may consider it to be visible only once it is initialized.
Therefore some external debuggers may fail on VisualAge for Java output when attempting to display variables which are not yet bound to a value (for example, trying to display the content of an array which has not yet been defined). The VisualAge for Java debugger handles this case correctly.
Due to the VisualAge for Java algorithm for assigning visibility ranges, a debugger may order local variables differently when using VisualAge for Java output than when using another compiler's output.
The Inner Classes Specification does not cover the full implementation details.
1.5.1 Default abstract methods
A compiler should produce default abstract methods for any abstract class that does not implement or inherit implementations methods
defined in the abstract class' superinterfaces. VisualAge for Java correctly produces these default abstract methods for top level and
type member classes; however, these methods are not produced for
local types. If this condition should occur, a compilation error is reported. To work around this limitation, simply explicitly define
the necessary abstract methods in the abstract local class.
1.5.2 Imports in default package
If type members are imported in a type from a default package, a warning is incorrectly reported notifying the developer that the
package does not exist. This warning should be ignored.
1.5.3 Explicit qualification
VisualAge for Java does not request explicit qualification for implicit use of inherited methods, when it is hiding an enclosing one. VisualAge for Java
considers inherited methods prior to enclosing ones without issuing an error (note that qualifying explicitly the code would be accepted
as well).
Here is a example of such a case, the implicit access to foo() should yield a complaint:
public class MethodQualification {
void foo() {
System.out.println("Inherited foo() for anonymous type");
class Local {
void foo(){
System.out.println("Enclosing foo() for anonymous type");
// should request explicit qualification
new MethodQualification () { {foo();} };
}
};
}
}
another example involving fields :
public class FieldQualification {
String field = "Inherited field for anonymous type";
void foo() {
class Local {
String field = "Enclosing field for anonymous type";
void foo() {
new FieldQualification() {
{
// should request explicit qualification
System.out.println(field);
}
};
}
};
}
}
1.5.4 this.super()
Some compilers allow constructors to contain super invocation of the form "this.super()". VisualAge for Java rejects this because it is not legal
to use this in a constructor invocation.
1.5.5 Access to synthetic names
VisualAge for Java does allows the use of $ names to refer to nested types. In addition, VisualAge for Java allows the use of $ names to access synthetic
fields. Do not use these names.
1.5.6 Method overloading
The inner class specification notes that class scoping does not influence overloading. VisualAge for Java searches through enclosing types
until an applicable method is found. If a method with the intended name, but that does not have the correct number of arguments is
found, it is ignored, and the search is continued. Some compilers stop when reaching this type of method.
1.5.7 Anonymous type modifiers
Some compilers treat anonymous inner types as final types with respect to casting conversion. VisualAge for Java does not do this;
therefore some casting conversion problems may only be detected at runtime, as shown in the following example:
class CheckInstanceOf {
void v() {
new Object() {
// should complain on the instanceof check at compile-time
boolean b = this instanceof Runnable;
};
}
}
1.5.8 Visibility of sibling classes
The rules determining the visibility of sibling classes will report an error anytime a local type is defined with the same name as
a sibling member type. In the following example, M2 defined as a local type is actually in conflict with the sibling member class,
which is also visible and bound as M1's superclass. VisualAge for Java reports this error.
class ExportedNames {
void foo() {
class Local {
class M1 extends M2 {
void bar() {
class M2 {} // M2 already defined
}
}
class M2 {}
}
}
}
1.5.9 Accessing static fields from a static member type
VisualAge for Java does not resolve fields of qualified member types such as X.Y.h correctly.
package test;
public class X {
public static class Y {
public static String h = "hello";
}
}
To refer to the static variable X.Y.h, first add the single type import:
import test.X.Y;
public class Z {
String a = test.X.Y.h; // fails to resolve Y correctly
String b = Y.h; // work-around
}
1.6.1 Circular constructor invocation
It is a compile-time error for a constructor to directly or indirectly invoke itself through a series of one or more explicit
constructor invocations involving 'this'. Only the direct invocation case is detected in the current implementation.
1.6.2 Incompatible interfaces
It is a compile-time error to cast an interface T to an interface S if S and T contain methods with the same signature but different
return types. This error is not detected at compile time, but at run-time, and a class cast exception is thrown.
1.6.3 Class and method collisions
During source file import, class and method collisions are silently ignored. The last definition in the file is used. This also occurs
if the class definition contains two definitions of a single method.
1.6.4 Method ordering on export
When exporting code, the ordering of methods may not be the same as during the initial import, nor the previous export, thus no
assumption should be made on the method ordering in exported source files or class files. Field ordering is preserved.
1.6.5 Type visibility in a default package
Classes defined in a default package are only visible within the default package. It is not possible to access these classes from
outside the default package.
1.6.6 Empty statements
Empty statements are ignored. Therefore, the compiler does not report unreachable code errors on unreachable empty statements. The
following methods exhibits this behavior:
void f () {
return;
label: ;
}
void g () {
return;
;;;;;
}
In addition, semicolons are silently ignored when included in a class definition. Therefore. the compiler accepts
the following class definition:
class C {
;;;;
}
1.6.7 Simple name imports
An import of a simple name is ignored. No errors are detected or reported, and the import is ignored during name resolution.
1.6.8 Protected constructor visibility
It is an error for a protected constructor to be invoked from another package, even if the type is a subclass of the type defining the
constructor. VisualAge for Java detects and reports this error.
1.6.9 Numeric underflow
VisualAge for Java does not report compile time numeric underflow. Therefore the following incorrect code is accepted:
double ds =1.0E-326;
This expression has a value of 0.0.
1.6.10 Definite assignment in dead code
Definite assignment in conditionals is handled differently depending on compiler implementations. VisualAge for Java will detect dead code
and not propagate initializations outside the dead code. Note that definite assignment rules for an IF statement enforce that even
though the code inside the dead branch is unreachable, it is not reported as such and is silently eliminated during code generation.
class DeadCode1 {
final static boolean Debug = false;
int foo() {
final int i;
if (Debug) i = 1;
i = 2; // some compilers complain about a duplicate assignment.
return i;
}
}
In the following example, VisualAge for Java reports that the assignment 'k = i' is using an uninitialized variable, and since this
assignment is in dead code, it actually never occurs and therefore the next assignment statement sets the local 'k' for the first time.
class DeadCode2 {
final static boolean Debug = false;
int foo() {
int i;
final int k;
if (Debug) { k = i; } // local i may not be initialized.
k = 1;
return k;
}
}
In the following example, VisualAge for Java only reports the use of an uninitialized variable.
class DeadCode3 {
final static boolean Debug = false;
int foo() {
int i;
final int k;
if (false) { k = i; }
if (false) { k = 1; }
k = 1;
return k;
}
}
1.6.11 Assignment conversion
VisualAge for Java does not provide an implicit narrowing conversion for constant expressions from char to byte.
The following statements are not accepted by VisualAge for Java:
byte b = 'a'; // JLS 5.2
byte[] ar = {'a'}; // JLS 5.2, 10.6
1.6.12 Incremental compiler may produce conflicting serialVersionUID
To facilitate incremental compilation, synthetic fields and methods are not created. Although this usually does not impact program
execution, it may impact the serialVersionUID (since the synthetic methods are considered when computing the serialVersionUID
for the class). When this condition arises, objects serialized in
the IDE will not be readable by another runtime. There are two ways to produce consistent serialVersionUID's everywhere. First,
define a static long field serialVersionUID that records the serialization hash. Second, if editing the source is not
a viable solution, export the necessary classes as .class files and then re-import them.
1.6.13 Static final variable dependency analysis
If a static final variable depends on the value of a static final variable defined in another class, then changing the second
variable's value does not cause the initial variable's value to change. To work
around this problem, delete and add the offending project, package, or type. Any dependency error can be resolved
using this work-around.
1.6.14 Side effects of copy/rename
When a package or class is copied or renamed, qualified references to the changed package or class are not edited.
Problems are reported to show you where the code must be changed.
The search engine examines the .class file information associated with the class. There are times when the results of such a search
can provide non-intuitive results. In particular, a constructor reports that it references a type if the field initializer for that
type in the class definition references a type. This occurs because the instance field initializers become part of the constructor at
compile time.
If the search engine finds an inner type, it answers the enclosing type or enclosing method as the result. The inner type can then be
found in the enclosing type or enclosing method.
VisualAge for Java computes the referenced types and referenced projects given a starting class. The mechanism for doing this is similar to the search engine described above. There are a few limitations with the current solution. First, references to a class by name are not considered a reference to the class. For example, the expression Class.forName("MyPackage.MyClass") does not report a reference to MyPackage.MyClass. Second, the referenced types algorithm does not include types that are only found in method signatures. This is not a limitation for programs since a program always provides an argument of the appropriate type. However, if you are exporting a framework, it is possible that some types may be omitted. Finally, if there are errors in the classes that are being searched for referenced types, the operation fails. To work around this problem, add the missing types.
For each project in the workspace, a corresponding resources directory is created. This directory is named with the project name.
If the project name is not a valid directory name, most likely because the name was too long, the directory will not be created and
a message will be written to the log.
In the Enterprise edition of VisualAge for Java, the Administrator can change the owner of the system projects to another user. It is strongly
recommended that the Administrator does not change this unnecessarily.
VisualAge for Java manages both source and binary (.class file) classes. Binary classes are not verified on import. It is assumed that only valid class files are imported. A system error may be reported if an invalid class file is imported. The compiler validates the superclass and superinterfaces of the binary class, and also the fields when the class is added to the workspace. The methods are not validated.