protected static Node getIdentifier(Node node) {
   if (node instanceof Tree.SpecifierStatement) {
     Tree.SpecifierStatement st = (Tree.SpecifierStatement) node;
     Tree.Term lhs = st.getBaseMemberExpression();
     while (lhs instanceof Tree.ParameterizedExpression) {
       Tree.ParameterizedExpression pe = (Tree.ParameterizedExpression) lhs;
       lhs = pe.getPrimary();
     }
     if (lhs instanceof Tree.StaticMemberOrTypeExpression) {
       Tree.StaticMemberOrTypeExpression mte = (Tree.StaticMemberOrTypeExpression) lhs;
       return mte.getIdentifier();
     } else {
       throw new RuntimeException("impossible");
     }
   } else {
     return getIdentifyingNode(node);
   }
 }
 @Override
 public void visit(Tree.SpecifierStatement that) {
   if (that.getRefinement()) {
     Tree.Term lhs = that.getBaseMemberExpression();
     if (lhs instanceof Tree.ParameterizedExpression) {
       Tree.ParameterizedExpression pe = (Tree.ParameterizedExpression) lhs;
       for (Tree.ParameterList pl : pe.getParameterLists()) {
         if (pl != null) {
           pl.visit(this);
         }
       }
       Tree.TypeParameterList tpl = pe.getTypeParameterList();
       if (tpl != null) {
         tpl.visit(this);
       }
     }
     // the LHS will be treated as a refinement by
     // FindRefinementsVisitor so ignore it here
     super.visit(that.getSpecifierExpression());
   } else {
     super.visit(that);
   }
 }
 @Override
 public void visit(Tree.SpecifierStatement that) {
   Tree.Term term = that.getBaseMemberExpression();
   boolean parameterized = false;
   while (term instanceof Tree.ParameterizedExpression) {
     Tree.ParameterizedExpression pe = (Tree.ParameterizedExpression) term;
     term = pe.getPrimary();
     parameterized = true;
   }
   if (term instanceof Tree.StaticMemberOrTypeExpression) {
     Tree.StaticMemberOrTypeExpression bme = (Tree.StaticMemberOrTypeExpression) term;
     //            Declaration member = getTypedDeclaration(bme.getScope(),
     //                    name(bme.getIdentifier()), null, false, bme.getUnit());
     Declaration member = bme.getDeclaration();
     if (member == declaration) {
       if ((declaration.isFormal() || declaration.isDefault()) && !isForwardReferenceable()) {
         // TODO: is this error correct?! look at the condition above
         bme.addError(
             "member is formal and may not be specified: '"
                 + member.getName()
                 + "' is declared formal");
       }
       if (that.getRefinement()) {
         declare();
       }
       Tree.SpecifierExpression se = that.getSpecifierExpression();
       boolean lazy = se instanceof Tree.LazySpecifierExpression;
       if (declaration instanceof Value) {
         Value value = (Value) declaration;
         if (!value.isVariable() && lazy != value.isTransient()) {
           // check that all assignments to a non-variable, in
           // different paths of execution, all use the same
           // kind of specifier, all =>, or all =
           // TODO: sometimes this error appears only because
           //       of a later line which illegally reassigns
           se.addError(
               "value must be specified using => lazy specifier: '" + member.getName() + "'");
         }
         if (lazy) {
           if (value.isVariable()) {
             se.addError(
                 "variable value may not be specified using => lazy specifier: '"
                     + member.getName()
                     + "'");
           } else if (value.isLate()) {
             se.addError(
                 "late reference may not be specified using => lazy specifier: '"
                     + member.getName()
                     + "'");
           }
         }
       }
       if (!lazy || !parameterized) {
         se.visit(this);
       }
       boolean constant = !isVariable() && !isLate();
       Scope scope = that.getScope();
       if (constant && !declaration.isDefinedInScope(scope)) {
         // this error is added by ExpressionVisitor
         //                    that.addError("inherited member is not variable and may not be
         // specified here: '" +
         //                            member.getName() + "'");
       } else if (!declared && constant) {
         bme.addError(shortdesc() + " is not yet declared: '" + member.getName() + "'");
       } else if (inLoop && constant && !(endsInBreakReturnThrow && lastContinue == null)) {
         if (specified.definitely) {
           bme.addError(
               longdesc() + " is aready definitely specified: '" + member.getName() + "'", 803);
         } else {
           bme.addError(
               longdesc() + " is not definitely unspecified in loop: '" + member.getName() + "'",
               803);
         }
       } else if (withinDeclaration && constant && !that.getRefinement()) {
         Declaration dec = getContainingDeclarationOfScope(scope);
         if (dec != null && dec.equals(member)) {
           bme.addError(
               "cannot specify "
                   + shortdesc()
                   + " from within its own body: '"
                   + member.getName()
                   + "'");
         } else {
           bme.addError(
               "cannot specify "
                   + shortdesc()
                   + " declared in outer scope: '"
                   + member.getName()
                   + "'",
               803);
         }
       } else if (specified.possibly && constant) {
         if (specified.definitely) {
           bme.addError(
               longdesc() + " is aready definitely specified: '" + member.getName() + "'", 803);
         } else {
           bme.addError(
               longdesc() + " is not definitely unspecified: '" + member.getName() + "'", 803);
         }
       } else {
         specify();
         term.visit(this);
       }
       if (lazy && parameterized) {
         se.visit(this);
       }
     } else {
       super.visit(that);
     }
   } else {
     super.visit(that);
   }
 }