Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 311639 - Multi-line constraints cause syntax error in generated validator class
Summary: Multi-line constraints cause syntax error in generated validator class
Status: VERIFIED FIXED
Alias: None
Product: EMF
Classification: Modeling
Component: Tools (show other bugs)
Version: unspecified   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: RC4   Edit
Assignee: Kenn Hussey CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 315352 (view as bug list)
Depends on:
Blocks:
 
Reported: 2010-05-04 18:16 EDT by Axel Uhl CLA
Modified: 2010-06-07 16:56 EDT (History)
4 users (show)

See Also:
Kenn.Hussey: helios+
Kenn.Hussey: pmc_approved+
Ed.Merks: pmc_approved+
Kenn.Hussey: review+
Ed.Merks: review+


Attachments
Generate a proper literal. (5.94 KB, patch)
2010-06-01 09:35 EDT, Ed Merks CLA
no flags Details | Diff
better patch (6.38 KB, patch)
2010-06-01 13:44 EDT, Kenn Hussey CLA
no flags Details | Diff
Fixes the indent method regarding subsequent escape chars (6.38 KB, patch)
2010-06-02 04:27 EDT, Axel Uhl CLA
no flags Details | Diff
final patch (5.98 KB, patch)
2010-06-02 09:28 EDT, Kenn Hussey CLA
no flags Details | Diff
final final patch (7.25 KB, patch)
2010-06-02 18:04 EDT, Kenn Hussey CLA
no flags Details | Diff
Fix for control problems (9.02 KB, patch)
2010-06-03 01:38 EDT, Ed Willink CLA
no flags Details | Diff
corrected final final patch :) (7.23 KB, patch)
2010-06-03 09:59 EDT, Kenn Hussey CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Axel Uhl CLA 2010-05-04 18:16:23 EDT
Build Identifier: 20100318-1801

When a constraint provided by a validator's annotation contains newlines, the ValidatorClass.javajet template generates uncompilable Java code. It may be helpful to replace newlines found in the annotation into \n escapes so as to generate compilable Java code. Below please find a possible patch that solves the problem in our case.

Index: src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenClassifierImpl.java
===================================================================
--- src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenClassifierImpl.java	(revision 652)
+++ src/org/eclipse/emf/codegen/ecore/genmodel/impl/GenClassifierImpl.java	(working copy)
@@ -325,7 +325,7 @@
 
   public String getConstraintExpression(String constraint, String indentation)
   {
-    return indent(getConstraintExpression(constraint), indentation);
+    return indent(getConstraintExpression(constraint).replace('\r', ' ').replace("\n", "\\n"), indentation);
   }
 
   public String getValidationDelegate(String constraint)


Reproducible: Always

Steps to Reproduce:
1. Create an Ecore model with a class that has an OCL constraint which contains newlines
2. Create a genmodel off of it
3. Generate the model code and try to compile the validator classes in the util package
Comment 1 Ed Merks CLA 2010-06-01 09:35:50 EDT
Created attachment 170633 [details]
Generate a proper literal.

Using multi-line support with indentation in this context just doesn't make sense.  A string literal is being produced and *all* special characters need escaping in this context. I think this must be changed before we release broken API.
Comment 2 Kenn Hussey CLA 2010-06-01 13:44:43 EDT
Created attachment 170667 [details]
better patch

Newlines were already being handled correctly for invariant expressions, so this patch applies the same strategy for constraints. Neither were properly escaping literals, however (ad Ed discovered when creating his patch); this patch ensures that the necessary escaping is also done.

Axel, please confirm that this updated patch will meet your needs.
Comment 3 Axel Uhl CLA 2010-06-02 04:27:50 EDT
Created attachment 170753 [details]
Fixes the indent method regarding subsequent escape chars
Comment 4 Ed Merks CLA 2010-06-02 07:47:09 EDT
*** Bug 315352 has been marked as a duplicate of this bug. ***
Comment 5 Ed Willink CLA 2010-06-02 08:29:53 EDT
(In reply to comment #4)
> *** Bug 315352 has been marked as a duplicate of this bug. ***

The duplicate has a much simpler patch.

It's not the indent() method as such that is the problem. It's the indenting of multiple lines, so indent() can be left as-is. Literals.toStringLiteral() can make the constraint string safe to indent.
Comment 6 Ed Merks CLA 2010-06-02 08:44:48 EDT
Yes, it's simpler to simply escape all the characters to produce one large string---my original obsoleted patch did that---but if one has an expression with dozens of lines, each very long, then producing a single huge line is not as desirable as producing a literal per line. 

Note that with your patch, the call to indent is pointless given that the string can no longer contain actual \n or \r characters; they've been escaped.
Comment 7 Ed Willink CLA 2010-06-02 09:15:05 EDT
(In reply to comment #6)
> Note that with your patch, the call to indent is pointless given that the
> string can no longer contain actual \n or \r characters; they've been escaped.

Indeed. My patch was as simple as possible to minimise RC4 risk.

We can certainly do better; changing indent() might ripple...

I'll try the new patch this evening.
Comment 8 Kenn Hussey CLA 2010-06-02 09:28:56 EDT
Created attachment 170797 [details]
final patch

Thanks, Axel, for the corrections. Here's a proposed "final" patch. If everyone is OK with this, I'll commit the changes ASAP.
Comment 9 Ed Willink CLA 2010-06-02 16:43:46 EDT
The patch is functional for me (so a +1 for utility, but only +0.5 for accuracy). The Java literal omits the \n and \r characters so the  literal does not accurately represent the Ecore content.

e.g. For an ValidationDelegate I get:

protected static final String MEMBER__AT_MOST_TWO_LOANS__EEXPRESSION = "" +
	"\t\t" +
	"\t\t" +
	"\t\tloans->size() <= 2";

whereas in the annotations I get:

addAnnotation
  (getBook_Loans(), 
   source, 
   new String[] {
	 "derivation", "\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\tlibrary.loans->\n      select(book=self)"
   });			
addAnnotation
  (memberEClass, 
   source, 
   new String[] {
	 "AtMostTwoLoans", "\n\t\t\n\t\t\n\t\tloans->size() <= 2",
	 "UniqueLoans", "\n\t\t\n\t\t\n\t\tloans->isUnique(book)"	   });		

Pretty printing is nice but it should be accurate.

[The above unfortunately demonstrates that the xxx__EEXPRESSION was not actually required at all. The AtMostTwoLoans body is code generated in two different ways.]
Comment 10 Axel Uhl CLA 2010-06-02 17:31:02 EDT
I hadn't checked that, but it's obvious that this will lead to bugs. Consider OCL expressions that contain line comments introduced with "--" leading up to the end of the line. This means, line breaks *have* to be preserved in the string literal.
Comment 11 Kenn Hussey CLA 2010-06-02 18:04:02 EDT
Created attachment 170889 [details]
final final patch

OK, how about this?
Comment 12 Ed Willink CLA 2010-06-03 01:38:33 EDT
Created attachment 170912 [details]
Fix for control problems

-1 to the "final final patch".

The increments needed to be 4:2 not 3:1 since the -1 shouldn't be done twice. (The trailing " of the indentation was being escaped.)

The attached patch separates the two concerns of

a) change the string
b) repair the loop counter

by using a to-go loop counter that doesn't need repair.

This eliminates the opportunity for the control logic error and makes the code a bit smaller and faster and simpler.
Comment 13 Kenn Hussey CLA 2010-06-03 09:37:17 EDT
(In reply to comment #12)
> The increments needed to be 4:2 not 3:1 since the -1 shouldn't be done twice.

Yeah, I somehow forgot that the increment already accounted for the -1.

> The attached patch separates the two concerns of
> 
> a) change the string
> b) repair the loop counter
> 
> by using a to-go loop counter that doesn't need repair.

Hmm. Doesn't it still need repair in the case that two characters are replaced instead of one?

Given how different the alternative patch is, I'm inclined to just commit my latest patch, with the corrected indexes.
Comment 14 Kenn Hussey CLA 2010-06-03 09:59:53 EDT
Created attachment 170957 [details]
corrected final final patch :)

If there are no objections, I will commit this first thing tomorrow (Friday).
Comment 15 Ed Willink CLA 2010-06-03 13:33:24 EDT
(In reply to comment #14)
+1
(In reply to comment #13)
> Hmm. Doesn't it still need repair in the case that two characters are replaced
> instead of one?

Yes. Oops. We have no JUnit test and I only exercised it with \n not \r\n.

In place updates and loop counter modifications are always difficult; in combination as here they're fatal. We've both messed up.

Sometimes I've created a local CharStream to eliminate the loop counter and allow multi-intra-loop-reads and passing to subroutines.

Often I use a separate output buffer to avoid input/output interactions.

I think we need at least a separate output buffer.
Comment 16 Kenn Hussey CLA 2010-06-04 10:15:25 EDT
The changes have been committed to CVS.
Comment 17 Kenn Hussey CLA 2010-06-07 16:56:10 EDT
This fix is available in 2.6.0 RC4.